<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>PostgreSQL内功修炼 on 最后的DBA</title><link>https://lastdba.com/categories/postgresql%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/</link><description>Recent content in PostgreSQL内功修炼 on 最后的DBA</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><copyright>© 2026 liuzhilong62</copyright><lastBuildDate>Fri, 29 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://lastdba.com/categories/postgresql%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/index.xml" rel="self" type="application/rss+xml"/><item><title>UUIDv4和v7两篇精彩文章-碰撞和性能</title><link>https://lastdba.com/2026/05/29/uuidv4%E5%92%8Cv7%E4%B8%A4%E7%AF%87%E7%B2%BE%E5%BD%A9%E6%96%87%E7%AB%A0-%E7%A2%B0%E6%92%9E%E5%92%8C%E6%80%A7%E8%83%BD/</link><pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/05/29/uuidv4%E5%92%8Cv7%E4%B8%A4%E7%AF%87%E7%B2%BE%E5%BD%A9%E6%96%87%E7%AB%A0-%E7%A2%B0%E6%92%9E%E5%92%8C%E6%80%A7%E8%83%BD/</guid><description>&lt;blockquote&gt;&lt;p&gt;素材来源：&lt;a href="https://news.ycombinator.com/item?id=48060054" target="_blank" rel="noreferrer"&gt;HN UUID v4 碰撞帖&lt;/a&gt;、&lt;a href="https://dev.to/umangsinha12/postgresql-uuid-performance-benchmarking-random-v4-and-time-based-v7-uuids-n9b" target="_blank" rel="noreferrer"&gt;dev.to UUID Benchmark&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;AI率99%&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 class="relative group"&gt;太长不看
 &lt;div id="太长不看" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%aa%e9%95%bf%e4%b8%8d%e7%9c%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;UUID v4 碰撞了——HackerNews 上有人真的撞了。原因是软件栈的 bug，不是数学。v4 和 v7 在碰撞安全性上没本质区别，差异在索引性能：v7 有时序，B-tree 更紧凑，写入快 35%、索引小 22%。你的 UUID v4 大概率没事，但如果你追求索引性能，换 v7 有实惠。&lt;/p&gt;</description><content:encoded>&lt;blockquote&gt;&lt;p&gt;素材来源：&lt;a href="https://news.ycombinator.com/item?id=48060054" target="_blank" rel="noreferrer"&gt;HN UUID v4 碰撞帖&lt;/a&gt;、&lt;a href="https://dev.to/umangsinha12/postgresql-uuid-performance-benchmarking-random-v4-and-time-based-v7-uuids-n9b" target="_blank" rel="noreferrer"&gt;dev.to UUID Benchmark&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;AI率99%&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 class="relative group"&gt;太长不看
 &lt;div id="太长不看" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%aa%e9%95%bf%e4%b8%8d%e7%9c%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;UUID v4 碰撞了——HackerNews 上有人真的撞了。原因是软件栈的 bug，不是数学。v4 和 v7 在碰撞安全性上没本质区别，差异在索引性能：v7 有时序，B-tree 更紧凑，写入快 35%、索引小 22%。你的 UUID v4 大概率没事，但如果你追求索引性能，换 v7 有实惠。&lt;/p&gt;

&lt;h3 class="relative group"&gt;UUID v4 碰撞事故
 &lt;div id="uuid-v4-碰撞事故" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#uuid-v4-%e7%a2%b0%e6%92%9e%e4%ba%8b%e6%95%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;HackerNews 上有个帖子火了——&lt;a href="https://news.ycombinator.com/item?id=48060054" target="_blank" rel="noreferrer"&gt;Ask HN: We just had an actual UUID v4 collision&amp;hellip;&lt;/a&gt;，479 赞 347 评论。&lt;/p&gt;
&lt;p&gt;发帖人的原话：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I know what you&amp;rsquo;re thinking&amp;hellip; and I still can&amp;rsquo;t believe it, but&amp;hellip; This morning, our database flagged a duplicate UUID (v4).&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;不是 double-insert 的 bug，不是代码写了两遍。库里只有 ~15,000 条记录，用 npm 的 &lt;code&gt;uuid&lt;/code&gt; 包生成 &lt;code&gt;uuidv4()&lt;/code&gt;，两个不同时间创建的行撞了同一个 UUID：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b6133fd6-70fe-4fe3-bed6-8ca8fc9386cd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;UUID v4 碰撞的概率是多少？122 位随机位，2^122 ≈ 5.3×10^36 种可能，15,000 条记录下碰撞概率约 2×10^-29。理论上&amp;quot;不可能&amp;quot;。&lt;/p&gt;
&lt;p&gt;但它发生了。&lt;/p&gt;

&lt;h4 class="relative group"&gt;原因一：熵源不可靠
 &lt;div id="原因一熵源不可靠" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e4%b8%80%e7%86%b5%e6%ba%90%e4%b8%8d%e5%8f%af%e9%9d%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;HN 最高赞评论（jandrewrogers）：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;UUIDv4 的安全性依赖高质量熵源。硬件缺陷、软件 bug、对&amp;quot;高质量熵&amp;quot;的误解，都会让这个假设失效。检测熵源故障很贵，所以没人检查——直到撞了。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;UUID v4 在高可靠系统中被&lt;strong&gt;明确禁止&lt;/strong&gt;，原因是无法验证熵源质量。&lt;/p&gt;

&lt;h4 class="relative group"&gt;原因二：npm uuid 包有已知 bug
 &lt;div id="原因二npm-uuid-包有已知-bug" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e4%ba%8cnpm-uuid-%e5%8c%85%e6%9c%89%e5%b7%b2%e7%9f%a5-bug" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;uuid npm 包的 README 自己都在警告：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This module may generate duplicate UUIDs when run in clients with deterministic random number generators, such as Googlebot crawlers.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;更严重的是，它的 &lt;code&gt;rng()&lt;/code&gt; 函数内部有全局可变状态。一个评论者指出：调用 &lt;code&gt;rng()&lt;/code&gt; 然后把结果发出去，等于&lt;strong&gt;覆盖了别人的随机数而且你能猜到它&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;相关 commit：&lt;a href="https://github.com/uuidjs/uuid/commit/91805f665c38b691ac2cbd" target="_blank" rel="noreferrer"&gt;91805f665c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;社区建议：用 Node.js 内置的 &lt;code&gt;crypto.randomUUID()&lt;/code&gt;，别用 npm uuid 包。&lt;/p&gt;

&lt;h4 class="relative group"&gt;原因三：Linux 内核 /dev/random 竞态
 &lt;div id="原因三linux-内核-devrandom-竞态" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e4%b8%89linux-%e5%86%85%e6%a0%b8-devrandom-%e7%ab%9e%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;另一个评论：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;我在分布式系统的浸泡测试里碰到了 dup UUID。排查很久发现是 Linux 内核的一个竞态 bug——多处理器系统上，两个进程同时读 /dev/random，极低概率（~百万分之一）拿到相同的字节。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 class="relative group"&gt;原因四：Go 的 UUID 库不检查返回值
 &lt;div id="原因四go-的-uuid-库不检查返回值" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e5%9b%9bgo-%e7%9a%84-uuid-%e5%ba%93%e4%b8%8d%e6%a3%80%e6%9f%a5%e8%bf%94%e5%9b%9e%e5%80%bc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;早期 Go UUID 库调用随机数函数时，不检查返回值长度。&amp;ldquo;请求 N 字节，返回了 3 字节&amp;quot;的情况在大部分硬件上不出现，所以没人检查，直到上生产环境撞了成千上万个重复 UUID。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 class="relative group"&gt;原因五：AMD CPU RNG 的历史缺陷
 &lt;div id="原因五amd-cpu-rng-的历史缺陷" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e4%ba%94amd-cpu-rng-%e7%9a%84%e5%8e%86%e5%8f%b2%e7%bc%ba%e9%99%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;AMD 某些 CPU 的内置随机数生成器曾经有问题。VM 环境还会&amp;quot;虚拟化掉&amp;quot;熵——虚拟机的时间源和熵源都可能退化。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;v4 和 v7 在碰撞安全性上没有本质区别，差异在前 48 位——v4 是随机数，v7 是时间戳。时序源出问题的情况你基本碰不到，随机源出问题的概率同样极低。HN 那个帖子是个有趣的特例，知道极少数人遇到了就行，不需要因此怀疑自己系统里的 UUID v4。&lt;/p&gt;
&lt;p&gt;选 v4 还是 v7，真正该看的不是碰撞，是&lt;strong&gt;索引性能&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;UUID v7 在 PG 16 中的性能对比
 &lt;div id="uuid-v7-在-pg-16-中的性能对比" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#uuid-v7-%e5%9c%a8-pg-16-%e4%b8%ad%e7%9a%84%e6%80%a7%e8%83%bd%e5%af%b9%e6%af%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;UUID v7 比 v4 在 PostgreSQL 里有一个实打实的优势：&lt;strong&gt;时序聚簇，B-tree 更友好&lt;/strong&gt;。v4 膨胀 v7 也能膨胀，区别只是 v7 的前 48 位有时序，insert 集中在 B-tree 右侧，页分裂少。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.to/umangsinha12/postgresql-uuid-performance-benchmarking-random-v4-and-time-based-v7-uuids-n9b" target="_blank" rel="noreferrer"&gt;Umang Sinha 的 benchmark&lt;/a&gt; 在 PG 16 Docker 容器（8 核 16GB NVMe）上做了严格的对比测试。&lt;/p&gt;

&lt;h4 class="relative group"&gt;测试条件
 &lt;div id="测试条件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e6%9d%a1%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; uuid_v4_test (id UUID &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, payload TEXT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; uuid_v7_test (id UUID &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, payload TEXT);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数&lt;/th&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;数据量&lt;/td&gt;
 &lt;td&gt;1000 万行/表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;批次&lt;/td&gt;
 &lt;td&gt;每批 1 万行&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;客户端&lt;/td&gt;
 &lt;td&gt;Go + pq 驱动&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UUID 预生成&lt;/td&gt;
 &lt;td&gt;在内存中生成好，不计时&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;性能结果
 &lt;div id="性能结果" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%a7%e8%83%bd%e7%bb%93%e6%9e%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;指标&lt;/th&gt;
 &lt;th&gt;UUID v4&lt;/th&gt;
 &lt;th&gt;UUID v7&lt;/th&gt;
 &lt;th&gt;提升&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;写入 1000 万行&lt;/td&gt;
 &lt;td&gt;5 分 35 秒&lt;/td&gt;
 &lt;td&gt;3 分 38 秒&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;35% 更快&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;表+索引总大小&lt;/td&gt;
 &lt;td&gt;3618 MB&lt;/td&gt;
 &lt;td&gt;3443 MB&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;5% 更小&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;B-tree 索引大小&lt;/td&gt;
 &lt;td&gt;776 MB&lt;/td&gt;
 &lt;td&gt;602 MB&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;22% 更小&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;单点查询&lt;/td&gt;
 &lt;td&gt;0.167 ms&lt;/td&gt;
 &lt;td&gt;0.038 ms&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;4.4 倍&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;范围扫描&lt;/td&gt;
 &lt;td&gt;8.283 ms&lt;/td&gt;
 &lt;td&gt;3.791 ms&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;2.2 倍&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;为什么差这么多
 &lt;div id="为什么差这么多" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e5%b7%ae%e8%bf%99%e4%b9%88%e5%a4%9a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;

 


&lt;img src="https://lastdba.com/img/uuid-v4-structure.png" alt="UUID v4 bit structure" /&gt;&lt;/p&gt;
&lt;p&gt;

 


&lt;img src="https://lastdba.com/img/uuid-v7-structure.png" alt="UUID v7 bit structure" /&gt;&lt;/p&gt;
&lt;p&gt;UUID v4 是完全随机的。新插入的 UUID 在 B-tree 索引里随机分布，导致大量页分裂（page split），索引碎片化严重。UUID v7 前 48 位是毫秒级时间戳，新生成的 UUID 天然有序——写入集中在 B-tree 的右侧，页分裂大幅减少，索引更紧凑。&lt;/p&gt;
&lt;p&gt;索引小 22% 不是魔法，是&lt;strong&gt;减少了碎片&lt;/strong&gt;。单点查询快 4 倍也不奇怪——B-tree 层级更少、缓存命中率更高。&lt;/p&gt;

&lt;h3 class="relative group"&gt;总结
 &lt;div id="总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;UUID v4 和 v7 在碰撞安全性上是一样的——都依赖熵源质量，一个用随机数填充前 48 位，一个用时间戳。碰撞是极少数人在特定环境下踩到的坑，你的环境大概率没事，这个基本判断不用变。&lt;/p&gt;
&lt;p&gt;真正该琢磨的是&lt;strong&gt;索引性能&lt;/strong&gt;。v7 的时序特性让 B-tree 更紧凑，实测写入快 35%、索引小 22%、查询快 2-4 倍。如果系统对 UUID 的写入量很大，换 v7 能省不少存储和 CPU。&lt;/p&gt;
&lt;p&gt;PG 18 会原生支持 &lt;code&gt;gen_uuid_v7()&lt;/code&gt;，目前可以应用层生成。不管用哪个版本，加 UNIQUE 约束总是对的。&lt;/p&gt;</content:encoded></item><item><title>从collation mismatch异常到其原理</title><link>https://lastdba.com/2025/12/13/%E4%BB%8Ecollation-mismatch%E5%BC%82%E5%B8%B8%E5%88%B0%E5%85%B6%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 13 Dec 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/12/13/%E4%BB%8Ecollation-mismatch%E5%BC%82%E5%B8%B8%E5%88%B0%E5%85%B6%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 class="relative group"&gt;问题现象
 &lt;div id="问题现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%ae%e9%a2%98%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;物理迁移信创后pg log偶有报错，版本是pg15：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WARNING: 01000: collation &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; has version mismatch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The collation in the database was created using version 2.17, but the operating system provides version 2.28.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Rebuild all objects affected by this collation and run ALTER COLLATION pg_catalog.&lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; REFRESH VERSION, or build RaseSQL with the right library version.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOCATION: pg_newlocale_from_collation, pg_locale.c:1660&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;前景：物理切换的时候做了失效索引重建和refresh database collation version。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;问题现象
 &lt;div id="问题现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%ae%e9%a2%98%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;物理迁移信创后pg log偶有报错，版本是pg15：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WARNING: 01000: collation &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; has version mismatch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The collation in the database was created using version 2.17, but the operating system provides version 2.28.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Rebuild all objects affected by this collation and run ALTER COLLATION pg_catalog.&lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; REFRESH VERSION, or build RaseSQL with the right library version.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOCATION: pg_newlocale_from_collation, pg_locale.c:1660&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;前景：物理切换的时候做了失效索引重建和refresh database collation version。&lt;/p&gt;
&lt;p&gt;虽然物理迁移后libc版本升了，但是做了索引重建的，索引现在是有效的，而且db中的collation version已经与OS libc一致。&lt;/p&gt;
&lt;p&gt;所以，&lt;/p&gt;
&lt;p&gt;为什么会报错？&lt;/p&gt;
&lt;p&gt;报错哪里触发的？&lt;/p&gt;
&lt;p&gt;报错有什么影响？&lt;/p&gt;
&lt;p&gt;怎么解决？&lt;/p&gt;

&lt;h2 class="relative group"&gt;问题分析
 &lt;div id="问题分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%ae%e9%a2%98%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;为什么会报错？
 &lt;div id="为什么会报错" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e6%8a%a5%e9%94%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;数据库内部的collation主要看3块：db、列、索引。前两个都是默认collation，索引的collation才是真collation。&lt;/p&gt;
&lt;p&gt;先检查database的collation，db的都是en_US.UTF8，且已经refresh database collation过了，所以“collation &amp;ldquo;zh_CN.utf8&amp;rdquo; has version mismatch”这个报错不应该在db层抛出。&lt;/p&gt;
&lt;p&gt;然后再查看字段没有特殊指定的默认collation：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; attrelid,attname,attcollation &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_attribute &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; attcollation &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;950&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;951&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attrelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; attname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; attcollation 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;0表示没有collation，default oid=100,C oid=950,POSIX oid=951；&amp;ldquo;zh_CN.utf8&amp;quot;肯定不会是这四个。&lt;/p&gt;
&lt;p&gt;最后再查看索引没有特殊指定的collation&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; indexrelid ,&lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(indcollation) coll &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index) i &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; coll &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;950&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;951&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; indexrelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; coll 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;排除db、字段、索引，那么只能是一种情况：业务层指定排序规则&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;)) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; l(col1) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WARNING: &lt;span style="color:#ae81ff"&gt;01000&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; has &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; mismatch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; was created &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;, but the operating &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt; provides &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Rebuild &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; objects affected &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; this &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; run &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATION&lt;/span&gt; pg_catalog.&lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; REFRESH &lt;span style="color:#66d9ef"&gt;VERSION&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; build RaseSQL &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;right&lt;/span&gt; library &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: pg_newlocale_from_collation, pg_locale.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1660&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个zh_CN.utf8的version就跟实际的不一致：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; collname,collversion,pg_collation_actual_version(oid) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.utf8&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collversion &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_collation_actual_version 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+-------------+-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不仅zh_CN.utf8不一样，所有都不一样（除了几个没有version说法的coll）&lt;/p&gt;
&lt;p&gt;所以很有可能是业务自己指定了一个排序规则&amp;quot;zh_CN.utf8&amp;rdquo;，但是库中的coll version与OS不一致，才抛出了报错。&lt;/p&gt;

&lt;h3 class="relative group"&gt;源码理解
 &lt;div id="源码理解" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%ba%90%e7%a0%81%e7%90%86%e8%a7%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;通过报错信息是很好定位到源码位置的，主要关注2个函数：&lt;code&gt;pg_newlocale_from_collation&lt;/code&gt;和&lt;code&gt;CheckMyDatabase&lt;/code&gt;。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;code&gt;pg_newlocale_from_collation&lt;/code&gt;缓存和检查&lt;code&gt;pg_collation&lt;/code&gt;
 &lt;div id="pg_newlocale_from_collation缓存和检查pg_collation" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_newlocale_from_collation%e7%bc%93%e5%ad%98%e5%92%8c%e6%a3%80%e6%9f%a5pg_collation" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;pg_newlocale_from_collation&lt;/code&gt;是pg10才有&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Create a locale_t from a collation OID. Results are cached for the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * lifetime of the backend. Thus, do not free the result with freelocale().
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * As a special optimization, the default/database collation returns 0.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Callers should then revert to the non-locale_t-enabled code path.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * In fact, they shouldn&amp;#39;t call this function at all when they are dealing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * with the default locale. That can save quite a bit in hotspots.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Also, callers should avoid calling this before going down a C/POSIX
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * fastpath, because such a fastpath should work even on platforms without
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * locale_t support in the C library.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * For simplicity, we always generate COLLATE + CTYPE even though we
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * might only need one of them. Since this is called only once per session,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * it shouldn&amp;#39;t cost much.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* locale_t指非ICU。该函数是为backend cache一个locale_t类型的collation OID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* the default/database collation returns 0。其中default表示使用db的collation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pg_locale_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pg_newlocale_from_collation&lt;/span&gt;(Oid collid) &lt;span style="color:#75715e"&gt;//注意传入的是collation的oid，不是拿所有pg_collation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Return 0 for &amp;#34;default&amp;#34; collation, just in case caller forgets */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (collid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; DEFAULT_COLLATION_OID) &lt;span style="color:#75715e"&gt;//有三个特殊的coll：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;pg_locale_t&lt;/span&gt;) &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#75715e"&gt;//default oid=100,C oid=950,POSIX oid=951
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (cache_entry&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;locale &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		collversion &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SysCacheGetAttr&lt;/span&gt;(COLLOID, tp, Anum_pg_collation_collversion,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									 &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;isnull); &lt;span style="color:#75715e"&gt;//从pg_collation中拿数据字典中的version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;isnull)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			actual_versionstr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_collation_actual_version&lt;/span&gt;(collform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;collprovider, collcollate); &lt;span style="color:#75715e"&gt;//通过get_collation_actual_version获得实际的version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			collversionstr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TextDatumGetCString&lt;/span&gt;(collversion);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(actual_versionstr, collversionstr) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//对比数据字典中的version和实际的version，不同就抛出报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;ereport&lt;/span&gt;(WARNING,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						(&lt;span style="color:#a6e22e"&gt;errmsg&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;collation &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt; has version mismatch&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#a6e22e"&gt;NameStr&lt;/span&gt;(collform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;collname)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 &lt;span style="color:#a6e22e"&gt;errdetail&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;The collation in the database was created using version %s, &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#e6db74"&gt;&amp;#34;but the operating system provides version %s.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 collversionstr, actual_versionstr),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 &lt;span style="color:#a6e22e"&gt;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Rebuild all objects affected by this collation and run &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER COLLATION %s REFRESH VERSION, &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#e6db74"&gt;&amp;#34;or build PostgreSQL with the right library version.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#a6e22e"&gt;quote_qualified_identifier&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;get_namespace_name&lt;/span&gt;(collform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;collnamespace),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;															&lt;span style="color:#a6e22e"&gt;NameStr&lt;/span&gt;(collform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;collname)))));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cache_entry&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;locale;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;主要是通过coll oid检查这个coll在pg_collation数据字典的version和实际的version是否一致，如果不一致就抛出报错。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;code&gt;CheckMyDatabase&lt;/code&gt;缓存和检查&lt;code&gt;pg_database&lt;/code&gt;
 &lt;div id="checkmydatabase缓存和检查pg_database" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#checkmydatabase%e7%bc%93%e5%ad%98%e5%92%8c%e6%a3%80%e6%9f%a5pg_database" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;CheckMyDatabase&lt;/code&gt;已经存在很久了，它要做很多db方面的检查。不过在pg15增加了检查db version的逻辑&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * CheckMyDatabase -- fetch information from the pg_database entry for our DB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;CheckMyDatabase&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name, &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; am_superuser, &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; override_allow_connections)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Fetch our pg_database row normally, via syscache */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	tup &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SearchSysCache1&lt;/span&gt;(DATABASEOID, &lt;span style="color:#a6e22e"&gt;ObjectIdGetDatum&lt;/span&gt;(MyDatabaseId));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	default_locale.provider &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dbform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;datlocprovider; &lt;span style="color:#75715e"&gt;//default就是db的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Default locale is currently always deterministic. Nondeterministic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * locales currently don&amp;#39;t support pattern matching, which would break a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * lot of things if applied globally.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	default_locale.deterministic &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true; &lt;span style="color:#75715e"&gt;//字节序敏感的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Check collation version. See similar code in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * pg_newlocale_from_collation(). Note that here we warn instead of error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * in any case, so that we don&amp;#39;t prevent connecting.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	datum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SysCacheGetAttr&lt;/span&gt;(DATABASEOID, tup, Anum_pg_database_datcollversion,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;isnull); &lt;span style="color:#75715e"&gt;//从pg_database中拿datcollversion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;isnull)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;actual_versionstr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;collversionstr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		collversionstr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TextDatumGetCString&lt;/span&gt;(datum);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		actual_versionstr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_collation_actual_version&lt;/span&gt;(dbform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;datlocprovider, dbform&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;datlocprovider &lt;span style="color:#f92672"&gt;==&lt;/span&gt; COLLPROVIDER_ICU &lt;span style="color:#f92672"&gt;?&lt;/span&gt; iculocale : collate); &lt;span style="color:#75715e"&gt;//通过get_collation_actual_version获得实际的version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(actual_versionstr, collversionstr) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//对比db datcollversion和实际的version，不相等则抛出warning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ereport&lt;/span&gt;(WARNING,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					(&lt;span style="color:#a6e22e"&gt;errmsg&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;database &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt; has a collation version mismatch&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							name),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 &lt;span style="color:#a6e22e"&gt;errdetail&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;The database was created using collation version %s, &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 &lt;span style="color:#e6db74"&gt;&amp;#34;but the operating system provides version %s.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 collversionstr, actual_versionstr),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 &lt;span style="color:#a6e22e"&gt;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Rebuild all objects in this database that use the default collation and run &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER DATABASE %s REFRESH COLLATION VERSION, &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 &lt;span style="color:#e6db74"&gt;&amp;#34;or build PostgreSQL with the right library version.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 &lt;span style="color:#a6e22e"&gt;quote_identifier&lt;/span&gt;(name))));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;CheckMyDatabase&lt;/code&gt;函数会对比数据字典pg_database中的datcollversion和实际的version。&lt;/p&gt;

&lt;h4 class="relative group"&gt;函数差异
 &lt;div id="函数差异" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%87%bd%e6%95%b0%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;在pg14及之前，对比collation的逻辑只有1个:会话首次缓存对应collation时，调用&lt;code&gt;pg_newlocale_from_collation&lt;/code&gt;访问&lt;strong&gt;pg_collation数据字典中的对应的那个collation的version&lt;/strong&gt;，对比真实的version&lt;/li&gt;
&lt;li&gt;在PG15及以后，因为在pg_database表中新增了datcollversion字段，所以新增了一个检查db collation version的逻辑：会话首次访问pg_database中的db时，调用&lt;code&gt;CheckMyDatabase&lt;/code&gt;检查&lt;strong&gt;pg_database中对应的那个db的datcollversion&lt;/strong&gt;，对比真实的version&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;为什么仅refresh database后报错不多
 &lt;div id="为什么仅refresh-database后报错不多" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bb%85refresh-database%e5%90%8e%e6%8a%a5%e9%94%99%e4%b8%8d%e5%a4%9a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;refresh database collation version后，不会触发pg_database的coll version不一致的warning，但是也不能排除pg_collation的coll version不一致的情况。为什么仅refresh database后，报错就少量这么多，难道pg_collation的coll version就不会被加载了?&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.coll,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(indcollation) coll &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index ) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.coll;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; coll &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;950&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; &lt;span style="color:#75715e"&gt;--C
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2841&lt;/span&gt; &lt;span style="color:#75715e"&gt;--不存在collation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;723&lt;/span&gt; &lt;span style="color:#75715e"&gt;--default&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;真实环境中，用的最多的还是default，一般也没人去指定collation，没有指定就是default，default就是db的默认collation。&lt;/p&gt;
&lt;p&gt;这里要回来再次关注&lt;code&gt;pg_newlocale_from_collation&lt;/code&gt;函数。函数刚开头是这样的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pg_locale_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pg_newlocale_from_collation&lt;/span&gt;(Oid collid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	collation_cache_entry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache_entry;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Callers must pass a valid OID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;OidIsValid&lt;/span&gt;(collid));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Return 0 for &amp;#34;default&amp;#34; collation, just in case caller forgets */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (collid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; DEFAULT_COLLATION_OID)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;pg_locale_t&lt;/span&gt;) &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当&lt;code&gt;collid==DEFAULT_COLLATION_OID&lt;/code&gt;==100时，直接&lt;code&gt;return&lt;/code&gt;，不再执行下面的真实version的判断，也就不会抛出warning。这个逻辑是合理的，因为db coll version已经在登入db时校验过了，如果有问题，那么肯定已经在session层抛出过一次warning了。&lt;/p&gt;
&lt;p&gt;另外，即便是传入可能的值collid=37，对应的C也没有version的说法。&lt;/p&gt;
&lt;p&gt;所以，refresh database后，绝大部分场景下，只要是用数据库内部的排序（非表达式排序和指定索引排序），就不会抛出报错了。&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试
 &lt;div id="测试" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这里仅测试是否有refresh warning，不测试索引corrupt或者库跑崩。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查看libc版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;getconf GNU_LIBC_VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;源主机版本 glibc 2.17
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;目标主机 glibc 2.28
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg版本 pg15+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;测试：刷db不刷新pg_collation，仅db coll version改变
 &lt;div id="测试刷db不刷新pg_collation仅db-coll-version改变" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%88%b7db%e4%b8%8d%e5%88%b7%e6%96%b0pg_collation%e4%bb%85db-coll-version%e6%94%b9%e5%8f%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; datname,datlocprovider,datcollate,datctype,datcollversion &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_database 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datlocprovider &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datctype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datcollversion 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+----------------+-------------+-------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; collname,collprovider,collversion,pg_collation_actual_version(oid) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;en_US.utf8&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collprovider &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collversion &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_collation_actual_version 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+--------------+-------------+-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; lzldb refresh &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NOTICE: &lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;: changing &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: AlterDatabaseRefreshColl, dbcommands.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2399&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再次查看pg_collation和pg_database&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collprovider &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collversion &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_collation_actual_version 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+--------------+-------------+-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datlocprovider &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datctype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datcollversion 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+----------------+-------------+-------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;跟官方文档的描述一致，refresh database collation version只是在刷db的默认collation，pg_collation本身是不会变的&lt;/p&gt;

&lt;h4 class="relative group"&gt;测试：刷db不刷新pg_collation，指定表达式排序报warning
 &lt;div id="测试刷db不刷新pg_collation指定表达式排序报warning" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%88%b7db%e4%b8%8d%e5%88%b7%e6%96%b0pg_collation%e6%8c%87%e5%ae%9a%e8%a1%a8%e8%be%be%e5%bc%8f%e6%8e%92%e5%ba%8f%e6%8a%a5warning" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;如开头分析，表达式排序会报warning，略&lt;/p&gt;

&lt;h4 class="relative group"&gt;测试：刷db不刷新pg_collation，新建指定collation的索引报warning
 &lt;div id="测试刷db不刷新pg_collation新建指定collation的索引报warning" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%88%b7db%e4%b8%8d%e5%88%b7%e6%96%b0pg_collation%e6%96%b0%e5%bb%ba%e6%8c%87%e5%ae%9acollation%e7%9a%84%e7%b4%a2%e5%bc%95%e6%8a%a5warning" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;测试1：建索引时指定collation&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collversion &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_collation_actual_version 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+-------------+-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx11 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tt(a &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WARNING: &lt;span style="color:#ae81ff"&gt;01000&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; has &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; mismatch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; was created &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;, but the operating &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt; provides &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Rebuild &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; objects affected &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; this &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; run &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATION&lt;/span&gt; pg_catalog.&lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; REFRESH &lt;span style="color:#66d9ef"&gt;VERSION&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; build PostgreSQL &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;right&lt;/span&gt; library &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: pg_newlocale_from_collation, pg_locale.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;测试2：建表时指定字段默认collation，建索引时不指定&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; lzldb &lt;span style="color:#75715e"&gt;--重连一个session
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; now connected &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; ttt(a varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxttt &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; ttt(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WARNING: &lt;span style="color:#ae81ff"&gt;01000&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; has &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; mismatch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; was created &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;, but the operating &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt; provides &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Rebuild &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; objects affected &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; this &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; run &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATION&lt;/span&gt; pg_catalog.&lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt; REFRESH &lt;span style="color:#66d9ef"&gt;VERSION&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; build PostgreSQL &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;right&lt;/span&gt; library &lt;span style="color:#66d9ef"&gt;version&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: pg_newlocale_from_collation, pg_locale.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;904&lt;/span&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;字段默认collation和建索引指定collation本质是一个东西，都是为了指定索引的collation。他们都可以报warning。&lt;/p&gt;

&lt;h4 class="relative group"&gt;测试：刷db不刷新pg_collation，已建指定collation的索引不报warning
 &lt;div id="测试刷db不刷新pg_collation已建指定collation的索引不报warning" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%88%b7db%e4%b8%8d%e5%88%b7%e6%96%b0pg_collation%e5%b7%b2%e5%bb%ba%e6%8c%87%e5%ae%9acollation%e7%9a%84%e7%b4%a2%e5%bc%95%e4%b8%8d%e6%8a%a5warning" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;场景为原库已经有索引指定collation zh_CN.utf8，跟db的不一样，refresh db刷不到。但是到新库后vendor的coll version肯定是变了。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; collname,collprovider,collversion,pg_collation_actual_version(oid) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.utf8&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collprovider &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collversion &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_collation_actual_version 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+--------------+-------------+-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不用表达式排序的话，可以用到索引，但是不能使用索引排序&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_seqscan &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXPLAIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANALYZE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; tt &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;LIMIT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------------------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Limit&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6667&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6670&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;928&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;145&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6667&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6892&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;81&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;90004&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;926&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;021&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort &lt;span style="color:#66d9ef"&gt;Method&lt;/span&gt;: top&lt;span style="color:#f92672"&gt;-&lt;/span&gt;N heapsort Memory: &lt;span style="color:#ae81ff"&gt;127&lt;/span&gt;kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxtt &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tt (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1732&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;98&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;90004&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;029&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;434&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;90004&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Heap Fetches: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;已建指定collation的索引，使用到的时候不报warning&lt;/p&gt;

&lt;h2 class="relative group"&gt;这个问题的总结
 &lt;div id="这个问题的总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%99%e4%b8%aa%e9%97%ae%e9%a2%98%e7%9a%84%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;refresh database和refresh collation的warning是session级。在每个会话中，对于每个db或每个collation只报一次。&lt;/p&gt;
&lt;p&gt;仅refresh database，很有可能不会再报warning，但是存在创建指定collation索引、运行指定表达式collation SQL时报warning的情况。&lt;/p&gt;
&lt;p&gt;数据字典中的coll version只是为了在db层追踪collation provider version是否发生改变。试想一下没有数据字典中的coll version，那么db可能都无法返回warning告知“你的排序规则提供商升级了版本，你的数据排序可能有问题，你需要检查一下了”（当然不止是排序）。&lt;/p&gt;

&lt;h2 class="relative group"&gt;这个问题的解决方案
 &lt;div id="这个问题的解决方案" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%99%e4%b8%aa%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;corrupt的索引已经重建过，db也refresh过，只是没有refresh collation。数据字典中的coll version不一致，问题不算太大，只是提示而已，至于还有其他什么隐秘又奇怪的坑，参考more章节。&lt;/p&gt;
&lt;p&gt;这个问题的解决方案：&lt;/p&gt;
&lt;p&gt;第一步：检查是否还有依赖&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; pg_describe_object(refclassid, refobjid, refobjsubid) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Collation&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_describe_object(classid, objid, objsubid) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Object&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_depend d &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; refclassid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pg_collation&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; refobjid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collversion &lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt; pg_collation_actual_version(&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果有返回，最好重建依赖的对象；没有的话遵循第二步：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方案一：不动。warning不多也可以不动&lt;/li&gt;
&lt;li&gt;方案二：仅refresh collation zh_CN.UTF8。来一个解决一个&lt;/li&gt;
&lt;li&gt;方案三：所有collation都refresh一遍。哪怕业务有增量使用表达式或索引指定collation，也不会报warning&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;more
 &lt;div id="more" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#more" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;glibc升级相关的精华总结
 &lt;div id="glibc升级相关的精华总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#glibc%e5%8d%87%e7%ba%a7%e7%9b%b8%e5%85%b3%e7%9a%84%e7%b2%be%e5%8d%8e%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;locale是一个非常坑的领域，glibc升级导致的collation的问题也非常多，参考ref资料，汇总一些比较重要的东西：&lt;/p&gt;
&lt;p&gt;pg_collation是从OS命令&lt;code&gt;locale -a&lt;/code&gt;取的；provider基本都是glibc，所以要看glibc的version。&lt;/p&gt;
&lt;p&gt;在pg_collation中&amp;quot;C&amp;quot;和&amp;quot;posix&amp;quot;的collprovider都是&lt;code&gt;c&lt;/code&gt;，看着跟“C.UTF8”等一样，其实不是的。“C.UTF8”的provider是glibc，&lt;strong&gt;有version，一般是unicode码点排序或unicode语义排序&lt;/strong&gt;；&amp;ldquo;C&amp;quot;和“POSIX”是等价的，是POSIX 标准定义的最基础的locale，由libc实现，不在&lt;code&gt;locale -a&lt;/code&gt;中，&lt;strong&gt;没有version，直接以字节序排序&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;collation问题的根源：数据库要的是数据库生命周期内locale定义永远不变，但是OS提供商特别是GNU C library每个小版本都会对locale做出改动，而且这是合法的。&lt;/p&gt;
&lt;p&gt;GNU C library每个小版本都会对locale做出改动，现实中最容易出问题的版本是&lt;strong&gt;glibc 2.28&lt;/strong&gt;，因为2.28升级了大版本&lt;strong&gt;unicode 9.0.0&lt;/strong&gt;(&lt;a href="https://sourceware.org/glibc/wiki/Release/2.28" target="_blank" rel="noreferrer"&gt;has been updated to a new upstream version from ISO which is in sync with Unicode 9.0.0&lt;/a&gt;)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg没有办法检测glibc升级带来的兼容性问题&lt;/strong&gt;。索引损坏检查不是all check，同时索引也只是一方面。物理复制或upgrade后，即使重建索引，也不能排除因为collation version的问题，某天库跑崩了的情况。&lt;/p&gt;
&lt;p&gt;数据异常包括：主键重复，依赖排序的约束，范围分区表数据写入错误分区，mergejoin等排序操作等等&lt;/p&gt;
&lt;p&gt;字符类型依赖collation，不依赖collation的数据类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bytea&lt;/li&gt;
&lt;li&gt;tsvector gin indexes&lt;/li&gt;
&lt;li&gt;pg_trgm indexes&lt;/li&gt;
&lt;li&gt;numeric data types: int, bigint, numeric, float, &amp;hellip;&lt;/li&gt;
&lt;li&gt;custom data types like geometry (PostGIS)&lt;/li&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ASCII排序比较常见但不符合人类理解，即不符合语义。符合语义的国际排序标准一般都是unicode标准。&lt;/p&gt;
&lt;p&gt;基于unicode的排序规则也分了好2种：码点排序、UCA（Unicode Collation Algorithm）&lt;/p&gt;
&lt;p&gt;UCA基于DUCET（Default Unicode Collation Element Table），DUCET表本身在不同版本间可能发生排序变化。举个栗子，en_US.UTF8是UCA排序，相当于语义排序，版本升级会改变排序规则。C.UTF8是码点排序，码点确认后不会改变，不会改变排序规则。&lt;/p&gt;
&lt;p&gt;PG 17+提供了非常安全的locale提供方式：builtin，不再依赖OS提供的glibc、ICU等provider。启用命令例如&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb &lt;span style="color:#75715e"&gt;--locale-provider=builtin --bultin-locale=C.UTF-8 dbname1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;17仅支持C, C.UTF-8，C是字节序排序（约等于ASCII排序），C.UTF-8是unicode码点排序；18多一个PG_UNICODE_FAST ，也是unicode码点排序，跟C.UTF-8&lt;a href="https://www.postgresql.org/docs/18/locale.html#LOCALE-PROVIDERS" target="_blank" rel="noreferrer"&gt;稍有区别&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;因为数据库必须保持排序稳定不变，业务自定义排序只有推给业务层实现，例如表达式排序就是语义明确的，而且不影响数据库本身对collation的选择。如果哪天pg也支持build-in en_US.utf8的话，再考虑build-in的语义排序。&lt;/p&gt;
&lt;p&gt;信创迁移时，信创主机的glibc版本一般都比老的英特尔服务器glibc版本高，很可能跨了2.28这个版本。加上任务急、kpi推动、人力不足和大库，物理迁移是在所难免。所以信创物理迁移得关注glibc版本和collation导致的许多异常。&lt;/p&gt;

&lt;h3 class="relative group"&gt;物理迁移后可以做什么
 &lt;div id="物理迁移后可以做什么" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%89%a9%e7%90%86%e8%bf%81%e7%a7%bb%e5%90%8e%e5%8f%af%e4%bb%a5%e5%81%9a%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;假设数据库是en_US.utf8，provider c，已经做了跨libc版本的物理迁移，应该做如下操作:&lt;/p&gt;
&lt;p&gt;一、官方必修方案&lt;/p&gt;
&lt;p&gt;1.至少要重建有问题的索引。安装amcheck插件，用bt_index_check函数&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; bt_index_check(&lt;span style="color:#e6db74"&gt;&amp;#39;idx1&amp;#39;&lt;/span&gt;::regclass, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.refresh database version，(pg15+)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; name REFRESH &lt;span style="color:#66d9ef"&gt;COLLATION&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VERSION&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;3.检查有没有其他&lt;a href="https://www.postgresql.org/docs/18/sql-altercollation.html#SQL-ALTERCOLLATION-NOTES" target="_blank" rel="noreferrer"&gt;依赖的对象&lt;/a&gt;，有的话得看情况处理了&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; pg_describe_object(refclassid, refobjid, refobjsubid) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Collation&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_describe_object(classid, objid, objsubid) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Object&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_depend d &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; refclassid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pg_collation&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; refobjid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collversion &lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt; pg_collation_actual_version(&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;处理完以后，再&lt;/p&gt;
&lt;p&gt;4.refresh collation version，(pg10+)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATION&lt;/span&gt; name REFRESH &lt;span style="color:#66d9ef"&gt;VERSION&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;二、非官方邪修方案&lt;/p&gt;
&lt;p&gt;我这没有做出完整的方案，只是一点思路。&lt;/p&gt;
&lt;p&gt;1.处理分区表写入错误分区的问题&lt;/p&gt;
&lt;p&gt;分区键是int/bigint/float，跟collation没有关系，可以不用管了&lt;/p&gt;
&lt;p&gt;分区键是时间分区，如果是timestamp不用管了，如果是varchar等等字符类型，就看情况了&lt;/p&gt;
&lt;p&gt;分区键是字符类型，参考“a”和“-”的排序（pgconf Collation Challenges Sorting It Out）。但要注意以下几点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果要查数据的话，不要从父表查，可能会崩或者查不出来&lt;/li&gt;
&lt;li&gt;没有简单的检测方案&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.处理主键/唯一键冲突&lt;/p&gt;
&lt;p&gt;3.处理fdw排序范围异常的问题&lt;/p&gt;
&lt;p&gt;4.未知问题&lt;/p&gt;

&lt;h2 class="relative group"&gt;ref
 &lt;div id="ref" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ref" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/Locale_data_changes" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Locale_data_changes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/Collations" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Collations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pgconf Collation Challenges Sorting It Out&lt;/p&gt;
&lt;p&gt;PFCONF Collations from A to Z&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.unicode.org/reports/tr10/tr10-34.html" target="_blank" rel="noreferrer"&gt;http://www.unicode.org/reports/tr10/tr10-34.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://sourceware.org/glibc/wiki/Release/2.28" target="_blank" rel="noreferrer"&gt;https://sourceware.org/glibc/wiki/Release/2.28&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/18/sql-altercollation.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/18/sql-altercollation.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/18/sql-alterdatabase.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/18/sql-alterdatabase.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/17/locale.html#LOCALE-PROVIDERS" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/17/locale.html#LOCALE-PROVIDERS&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>简评ORACLE,MYSQL,PG的逻辑复制</title><link>https://lastdba.com/2025/11/30/%E7%AE%80%E8%AF%84oraclemysqlpg%E7%9A%84%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6/</link><pubDate>Sun, 30 Nov 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/11/30/%E7%AE%80%E8%AF%84oraclemysqlpg%E7%9A%84%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6/</guid><description>&lt;h3 class="relative group"&gt;postgresql逻辑复制
 &lt;div id="postgresql逻辑复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgresql%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;​​​​


&lt;img src="https://lastdba.com/img/csdn/64e1d30f2123.png" alt="在这里插入图片描述" /&gt;
（https://www.pgconf.asia/JA/2017/wp-content/uploads/sites/2/2017/12/D2-A7-EN.pdf）&lt;/p&gt;</description><content:encoded>
&lt;h3 class="relative group"&gt;postgresql逻辑复制
 &lt;div id="postgresql逻辑复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgresql%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;​​​​


&lt;img src="https://lastdba.com/img/csdn/64e1d30f2123.png" alt="在这里插入图片描述" /&gt;
（https://www.pgconf.asia/JA/2017/wp-content/uploads/sites/2/2017/12/D2-A7-EN.pdf）&lt;/p&gt;
&lt;p&gt;PostgreSQL把所有逻辑解析相关的事情全部放在数据库中的复制槽进行管理，大包大揽。早期版本的逻辑复制支持的还不太好，近期的几个大版本中，逻辑复制是主要的功能提升之一。
PG方案的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非常灵活，把逻辑解码接口提供给用户，有多种类的解析方式&lt;/li&gt;
&lt;li&gt;用户可根据需求订阅所需要的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG方案的劣势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;知识点多学习成本相对MYSQL要高很多。仅仅是基础知识点：发布、订阅、walsender、复制槽、output plugin等等，我相信很多人没有弄明白他们概念和关系&lt;/li&gt;
&lt;li&gt;干最累的活挨最毒的打。逻辑解析的问题全部暴露在数据库中，wal积压、大事物、长事务、reorder事务排序、权限问题、流式传输等等都是PG要考虑的问题&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;mysql的binlog
 &lt;div id="mysql的binlog" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mysql%e7%9a%84binlog" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/668c1dc8ce20.png" alt="在这里插入图片描述" /&gt;
(&lt;a href="https://blog.fasterinfo.top/6243.html" target="_blank" rel="noreferrer"&gt;https://blog.fasterinfo.top/6243.html&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;mysql把所有解析出来的逻辑数据放在本地——binlog文件中，方案简单。&lt;em&gt;mysql的binlog约等于PostgreSQL开启全表逻辑复制并写入本地&lt;/em&gt;。
MYSQL方案的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;简单粗暴，mysql不把逻辑解码接口直接暴露给用户，而是把已解析出来的文件直接给到用户，用户不需要关心怎么解析的，直接读binlog文件即可&lt;/li&gt;
&lt;li&gt;生态成熟。个人认为mysql生态成熟跟binlog有较大关系，在互联网时代PG的逻辑复制还很弱，而binlog十分简单，下游解析binlog把数据放到其他平台已成为一种常见方案&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MYSQL方案的劣势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据必须全部解析，不可定制化订阅数据，灵活性差&lt;/li&gt;
&lt;li&gt;两阶段提交。由于mysql主从强依赖binlog，又导致binlog数据在提交的时候必须全部落盘到binlog file，一次提交必须写两份（或者两种）日志——binlog和redolog，日志双写是mysql永恒的痛点之一。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;oracle的逻辑复制
 &lt;div id="oracle的逻辑复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#oracle%e7%9a%84%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8978c46a1452.png" alt="在这里插入图片描述" /&gt;
（https://www.oracle-scn.com/oracle-goldengate-integrated-capture/）&lt;/p&gt;
&lt;p&gt;oracle本身是有逻辑DG的功能的，但基本上没见有人用过，这里只聊logminer 。oracle数据库本身提供了logminer这样的接口来解析日志（如OGG集成模式），逻辑复制链路管理本身完全没有，依赖第三方工具来创建和管理复制链路
ORACLE方案的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只提供解析接口，没有复制链路管理，对于数据库本身来说非常省心&lt;/li&gt;
&lt;li&gt;充值就有方案。把强大的OGG直接买下来，不要说我ORACLE没有提供逻辑复制解决方案，我们不仅有，而且很强大、认可度高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ORACLE方案的劣势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;依赖第三方软件管理复制链路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之，PG的逻辑复制是大包大揽什么都做，非常有开源精神、技术精神。MYSQL的方案简单粗暴但好用，有点“一步到位”的意思。ORACLE属于给个接口后就什么都不管，全部给第三方管理，但对于客户来说是有成熟的解决方案的。&lt;/p&gt;</content:encoded></item><item><title>查询冲突：从静态表查询冲突到其原理</title><link>https://lastdba.com/2025/09/13/%E6%9F%A5%E8%AF%A2%E5%86%B2%E7%AA%81%E4%BB%8E%E9%9D%99%E6%80%81%E8%A1%A8%E6%9F%A5%E8%AF%A2%E5%86%B2%E7%AA%81%E5%88%B0%E5%85%B6%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 13 Sep 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/09/13/%E6%9F%A5%E8%AF%A2%E5%86%B2%E7%AA%81%E4%BB%8E%E9%9D%99%E6%80%81%E8%A1%A8%E6%9F%A5%E8%AF%A2%E5%86%B2%E7%AA%81%E5%88%B0%E5%85%B6%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 class="relative group"&gt;问题现象
 &lt;div id="问题现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%ae%e9%a2%98%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;现象
 &lt;div id="现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一个静态历史表，没有任何更新，在同城从库跑SQL稳定触发查询冲突：&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;问题现象
 &lt;div id="问题现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%ae%e9%a2%98%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;现象
 &lt;div id="现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一个静态历史表，没有任何更新，在同城从库跑SQL稳定触发查询冲突：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;40001&lt;/span&gt;: canceling &lt;span style="color:#66d9ef"&gt;statement&lt;/span&gt; due &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; conflict &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; recovery
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: &lt;span style="color:#66d9ef"&gt;User&lt;/span&gt; query might have needed &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; see &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions that must be removed.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: ProcessInterrupts, postgres.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3197&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;30534&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;973&lt;/span&gt; ms (&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;535&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;为什么一个静态表查询冲突是一个值得关注的问题
 &lt;div id="为什么一个静态表查询冲突是一个值得关注的问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%80%e4%b8%aa%e9%9d%99%e6%80%81%e8%a1%a8%e6%9f%a5%e8%af%a2%e5%86%b2%e7%aa%81%e6%98%af%e4%b8%80%e4%b8%aa%e5%80%bc%e5%be%97%e5%85%b3%e6%b3%a8%e7%9a%84%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;我的理解中静态表是不应该发生冲突的（这个理解错了，后面会解释）。&lt;/p&gt;
&lt;p&gt;官方文档 Conflict cases include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access Exclusive locks taken on the primary server, including both explicit &lt;code&gt;LOCK&lt;/code&gt; commands and various DDL actions, conflict with table accesses in standby queries.&lt;/li&gt;
&lt;li&gt;Dropping a tablespace on the primary conflicts with standby queries using that tablespace for temporary work files.&lt;/li&gt;
&lt;li&gt;Dropping a database on the primary conflicts with sessions connected to that database on the standby.&lt;/li&gt;
&lt;li&gt;Application of a vacuum cleanup record from WAL conflicts with standby transactions whose snapshots can still “see” any of the rows to be removed.&lt;/li&gt;
&lt;li&gt;Application of a vacuum cleanup record from WAL conflicts with queries accessing the target page on the standby, whether or not the data to be removed is visible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LOCK,DDL,drop tablespace ,drop database肯定没有。&lt;/p&gt;
&lt;p&gt;vacuum，这也没有，这可以从pg_stat_all_tables.last_autovacuum和wal vacuum record可以看出来&lt;/p&gt;
&lt;p&gt;官方文档的解释就到此为止了，我自己仔细排查了一下确认没有以上情况。&lt;/p&gt;
&lt;p&gt;利用现有知识&lt;em&gt;可能&lt;/em&gt;还有其他场景干掉从库查询的所持有快照的xmin。例如页内修剪会干掉page中行上的xmin，如果下游的查询的快照还依赖这些xmin，这理论上也会发生查询冲突。但是，page是属于一个表的，只查一个表只能持有这个表上的快照以及表上的xmin，所以，&lt;em&gt;理论&lt;/em&gt;上A表的页内修剪，&lt;strong&gt;应该&lt;/strong&gt;不会发生B表上的查询冲突（这个理解错了，后面会解释）。&lt;/p&gt;
&lt;p&gt;pg官方文档对查询冲突场景的解释比较糊，没有很好的解释静态表发生冲突的场景和原因。加上自己联想的场景，也不应该有查询冲突。但我发现这个场景似乎在很多库上都有，所以得看下咋回事。&lt;/p&gt;

&lt;h2 class="relative group"&gt;原因分析
 &lt;div id="原因分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8e%9f%e5%9b%a0%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为是startup把查询掐掉的，所以看startup进程的pstack即可找到查询冲突函数&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pstack &lt;span style="color:#ae81ff"&gt;212012&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00002b283f63d783 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; __select_nocancel () &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt;lib64&lt;span style="color:#f92672"&gt;/&lt;/span&gt;libc.so.&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00000000008fcf5a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pg_usleep (microsec&lt;span style="color:#f92672"&gt;=&amp;lt;&lt;/span&gt;optimized &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; pgsleep.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000787905 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; WaitExceedsMaxStandbyDelay (wait_event_info&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;134217762&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; standby.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;208&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; ResolveRecoveryConflictWithVirtualXIDs (waitlist&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2398a50, reason&lt;span style="color:#f92672"&gt;=&lt;/span&gt;reason&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, wait_event_info&lt;span style="color:#f92672"&gt;=&lt;/span&gt;wait_event_info&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;134217762&lt;/span&gt;, report_waiting&lt;span style="color:#f92672"&gt;=&lt;/span&gt;report_waiting&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; standby.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;276&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000787b33 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ResolveRecoveryConflictWithVirtualXIDs (report_waiting&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, wait_event_info&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;134217762&lt;/span&gt;, reason&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, waitlist&lt;span style="color:#f92672"&gt;=&amp;lt;&lt;/span&gt;optimized &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; standby.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;333&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; ResolveRecoveryConflictWithSnapshot (latestRemovedXid&lt;span style="color:#f92672"&gt;=&amp;lt;&lt;/span&gt;optimized &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, node&lt;span style="color:#f92672"&gt;=&lt;/span&gt;...) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; standby.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;329&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00000000004c8ffe &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; heap_xlog_clean (record&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2366978) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; heapam.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;7764&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; heap2_redo (record&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2366978) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; heapam.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8917&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000519e55 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; StartupXLOG () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; xlog.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;7411&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000072f211 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; StartupProcessMain () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; startup.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;204&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00000000005286b1 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; AuxiliaryProcessMain (argc&lt;span style="color:#f92672"&gt;=&lt;/span&gt;argc&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, argv&lt;span style="color:#f92672"&gt;=&lt;/span&gt;argv&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x7ffeb7e39d70) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; bootstrap.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000072c369 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; StartChildProcess (&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;StartupProcess) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; postmaster.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;5494&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000072eb54 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; PostmasterMain (argc&lt;span style="color:#f92672"&gt;=&lt;/span&gt;argc&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, argv&lt;span style="color:#f92672"&gt;=&lt;/span&gt;argv&lt;span style="color:#f92672"&gt;@&lt;/span&gt;entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x232edb0) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; postmaster.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1407&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00000000004892cf &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; main (argc&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, argv&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x232edb0) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; main.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;210&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;XLOG_HEAP2_CLEAN
 &lt;div id="xlog_heap2_clean" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#xlog_heap2_clean" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;heap2_redo&lt;/span&gt;(XLogReaderState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;record)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint8		info &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;XLogRecGetInfo&lt;/span&gt;(record) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;XLR_INFO_MASK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (info &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; XLOG_HEAP_OPMASK)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; XLOG_HEAP2_CLEAN:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;heap_xlog_clean&lt;/span&gt;(record);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当redo是&lt;code&gt;XLOG_HEAP2_CLEAN&lt;/code&gt;时，才会进入这个下一个函数&lt;code&gt;heap_xlog_clean&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;pg 18已经没有&lt;code&gt;XLOG_HEAP2_CLEAN&lt;/code&gt;这个东西了（15左右其实就没有了，这篇文章就只看13和18两个版本），但是可以在heapam_xlog.h中找到define&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//pg13
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_CLEAN		0x10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_FREEZE_PAGE	0x20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_CLEANUP_INFO 0x30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//pg18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; There&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s no difference between XLOG_HEAP2_PRUNE_ON_ACCESS,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; XLOG_HEAP2_PRUNE_VACUUM_SCAN and XLOG_HEAP2_PRUNE_VACUUM_CLEANUP records.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; They have separate opcodes just &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; debugging and analysis purposes, to
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; indicate why the WAL record was emitted.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_PRUNE_ON_ACCESS		0x10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_PRUNE_VACUUM_SCAN	0x20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XLOG_HEAP2_PRUNE_VACUUM_CLEANUP	0x30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;把pg18的源码掏出来，主要是因为pg13（当前生产库的版本）对这几个xl_info 的CLEAN宏定义一点解释没有，我看不懂。由于18这段宏换了个更容易理解的名字，而且加上了注释，我们可以从18的源码来理解13，看看这个wal record是干什么的。&lt;/p&gt;
&lt;p&gt;这3个opcodes本质上都是为了PRUNE产生的wal record。从名字上看PRUNE ON ACCESS看着像访问产生PRUNE，另外两个跟VACUUM动作相关。&lt;/p&gt;
&lt;p&gt;用&lt;code&gt;pg_waldump&lt;/code&gt;查看wal record的时候，&lt;code&gt;rmgr: Heap2 CLEAN remxid&lt;/code&gt;这种record每几秒钟就生成几条，而且filenode差异很大，且跟静态表毫无关系：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pg_waldump &lt;span style="color:#ae81ff"&gt;00000001000012F&lt;/span&gt;E00000001 &lt;span style="color:#f92672"&gt;|&lt;/span&gt;tail &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;egrep &lt;span style="color:#f92672"&gt;-&lt;/span&gt;i heap2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_waldump: fatal: error in WAL record at &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F34F138: invalid resource manager ID &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; at &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F34F168
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap2 &lt;span style="color:#a6e22e"&gt;len&lt;/span&gt; (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3520&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0F&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;346&lt;/span&gt;ED0, prev &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0F&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;346&lt;/span&gt;EA0, desc: CLEAN remxid &lt;span style="color:#ae81ff"&gt;1983744188&lt;/span&gt;, blkref &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; rel &lt;span style="color:#ae81ff"&gt;1663&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;88121&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1083807&lt;/span&gt; blk &lt;span style="color:#ae81ff"&gt;617606&lt;/span&gt; FPW
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap2 &lt;span style="color:#a6e22e"&gt;len&lt;/span&gt; (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0F&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;BC60, prev &lt;span style="color:#ae81ff"&gt;12F&lt;/span&gt;E&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0F&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;BC30, desc: CLEAN remxid &lt;span style="color:#ae81ff"&gt;1984090598&lt;/span&gt;, blkref &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; rel &lt;span style="color:#ae81ff"&gt;1663&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;88121&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;504681&lt;/span&gt; blk &lt;span style="color:#ae81ff"&gt;1447147&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个就跟我们的现象有点匹配了：没有vacuum动作但是有PRUNE，可以走到后续&lt;code&gt;heap_xlog_clean&lt;/code&gt; &lt;code&gt;ResolveRecoveryConflictWithSnapshot&lt;/code&gt;等查询冲突主函数上去。&lt;/p&gt;
&lt;p&gt;PRUNE动作产生&lt;code&gt;rmgr: Heap2 CLEAN remxid&lt;/code&gt;walrecord后面会测试复现。&lt;/p&gt;
&lt;p&gt;先把源码撸完。&lt;/p&gt;

&lt;h3 class="relative group"&gt;ResolveRecoveryConflictWithSnapshot
 &lt;div id="resolverecoveryconflictwithsnapshot" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#resolverecoveryconflictwithsnapshot" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ResolveRecoveryConflictWithSnapshot&lt;/span&gt;(TransactionId latestRemovedXid, RelFileNode node)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	VirtualTransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;backends;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * If we get passed InvalidTransactionId then we do nothing (no conflict).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * This can happen when replaying already-applied WAL records after a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * standby crash or restart, or when replaying an XLOG_HEAP2_VISIBLE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * record that marks as frozen a page which was already all-visible. It&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * also quite common with records generated during index deletion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * (original execution of the deletion can reason that a recovery conflict
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * which is sufficient for the deletion operation must take place before
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * replay of the deletion record itself).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(latestRemovedXid))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	backends &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetConflictingVirtualXIDs&lt;/span&gt;(latestRemovedXid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 node.dbNode);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;ResolveRecoveryConflictWithVirtualXIDs&lt;/span&gt;(backends,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 PROCSIG_RECOVERY_CONFLICT_SNAPSHOT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查询冲突有几个类型，其中&lt;code&gt;ResolveRecoveryConflictWithSnapshot&lt;/code&gt;人如其名就是跟快照冲突了，&lt;/p&gt;
&lt;p&gt;其中&lt;code&gt;GetConflictingVirtualXIDs&lt;/code&gt;是找到哪些backends跟快照冲突。&lt;code&gt;ResolveRecoveryConflictWithVirtualXIDs&lt;/code&gt;主要是解决冲突，时间限制。&lt;/p&gt;

&lt;h3 class="relative group"&gt;GetConflictingVirtualXIDs
 &lt;div id="getconflictingvirtualxids" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#getconflictingvirtualxids" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GetConflictingVirtualXIDs&lt;/code&gt;是判断是否vxid backend发生查询冲突的关键函数，要稍微用点脑力。
关键函数解读所需要的基础知识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;limitXmin&lt;/code&gt;就是&lt;code&gt;latestRemovedXid&lt;/code&gt;，也就是wal中的 &lt;code&gt;CLEAN remxid&lt;/code&gt;，也就是需要被清理的xid（remxid我理解为remove xid）。&lt;code&gt;/*limitXmin is supplied as either latestRemovedXid, or InvalidTransactionId*/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PGPROC&lt;/code&gt;是当前进程信息，有backend id，databas id，锁信息等等很多东西&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PGXACT&lt;/code&gt;是当前进程持有的快照的事务信息，信息没有那么多，最关键的就是xmin——当前进程运行的最小xid&lt;/li&gt;
&lt;li&gt;c中&lt;code&gt;||&lt;/code&gt;的规则是：只要有一个操作数为真（非零），结果就为真（1）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TransactionIdIsValid&lt;/code&gt;即&lt;code&gt;xid!=0&lt;/code&gt;，0完全没有意义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键函数&lt;code&gt;GetConflictingVirtualXIDs&lt;/code&gt;解读：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VirtualTransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;GetConflictingVirtualXIDs&lt;/span&gt;(TransactionId limitXmin, Oid dbOid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (index &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; arrayP&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;numProcs; index&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//所有本地进程循环处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			pgprocno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; arrayP&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pgprocnos[index];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		PGPROC	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;proc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;allProcs[pgprocno]; &lt;span style="color:#75715e"&gt;//进程的PGPROC
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		PGXACT	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pgxact &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;allPgXact[pgprocno]; &lt;span style="color:#75715e"&gt;//进程的PGXACT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Exclude prepared transactions */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (proc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//prepared transaction没有进程持有，处理不了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OidIsValid&lt;/span&gt;(dbOid) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#75715e"&gt;//要注意全局的表，全局表的dbOid=0是invalid的，满足条件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			proc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;databaseId &lt;span style="color:#f92672"&gt;==&lt;/span&gt; dbOid) &lt;span style="color:#75715e"&gt;//只处理当前database。跨库是另一码事了，根本不会事务冲突。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Fetch xmin just once - can&amp;#39;t change on us, but good coding */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			TransactionId pxmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UINT32_ACCESS_ONCE&lt;/span&gt;(pgxact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmin); &lt;span style="color:#75715e"&gt;//pgxact-&amp;gt;xmin即是当前进程持有事务的最小xid，UINT32_ACCESS_ONCE只是为了保护原子操作，取xmin逻辑不变
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * We ignore an invalid pxmin because this means that backend has
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * no snapshot currently. We hold a Share lock to avoid contention
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * with users taking snapshots. That is not a problem because the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * current xmin is always at least one higher than the latest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * removed xid, so any new snapshot would never conflict with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * test here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(limitXmin) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#75715e"&gt;//limitXmin=0还能出现？至少latestRemovedXid不可能有，我想不到有什么场景会出现wal日志写入无效xid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(pxmin) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdFollows&lt;/span&gt;(pxmin, limitXmin))) &lt;span style="color:#75715e"&gt;//TransactionIdIsValid(pxmin)也没有什么用。!TransactionIdFollows(pxmin, limitXmin)表示只要pxmin&amp;lt;=limitXmin即可
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				VirtualTransactionId vxid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;GET_VXID_FROM_PGPROC&lt;/span&gt;(vxid, &lt;span style="color:#f92672"&gt;*&lt;/span&gt;proc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;VirtualTransactionIdIsValid&lt;/span&gt;(vxid))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					vxids[count&lt;span style="color:#f92672"&gt;++&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; vxid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;最关键的是&lt;code&gt;!TransactionIdFollows(pxmin, limitXmin)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以这段判断是否存在查询冲突的代码，最主要判断逻辑是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;主库清理的remxid&amp;gt;=从库查询的快照持有的最小xid&lt;/strong&gt;，即冲突。&lt;/li&gt;
&lt;li&gt;只掐掉当前db的；没有db的全局系统表就不管了会无脑掐&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以&lt;strong&gt;即使被清理的主库表和从库查询的表不相干，也会冲突！！！&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;页内修剪
 &lt;div id="页内修剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%a1%b5%e5%86%85%e4%bf%ae%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;发生冲突的逻辑理完了，但wal CLEAN 怎么来的还没有弄清楚，这就需要先看下PRUNE怎么产生的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;README.HOT&lt;/code&gt;关于什么时候产生prune和defragment的描述&amp;ndash; When can/should we prune or defragment?&lt;/p&gt;
&lt;p&gt;The currently planned heuristic is to prune and defrag when first accessing
a page that potentially has prunable tuples&lt;/p&gt;
&lt;p&gt;prune和defragment确实是2个概念，但是很有可能一起做了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prune指更新line pointers使HOT链更短，但不会释放空间&lt;/li&gt;
&lt;li&gt;defragment指回收prune后page上已死的line pointers和行所占用的空间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We cannot prune or defragment unless we can get a &amp;ldquo;buffer cleanup lock&amp;rdquo;
on the target page; otherwise, pruning might destroy line pointers that
other backends have live references to, and defragmenting might move
tuples that other backends have live pointers to&lt;/p&gt;
&lt;p&gt;page是&amp;quot;buffer cleanup lock&amp;quot;的，才会产生prune或者defragment&lt;/p&gt;
&lt;p&gt;The worst-case consequence of this is only that an
UPDATE cannot be made HOT but has to link to a new tuple version placed on
some other page, for lack of centralized space on the original page.&lt;/p&gt;
&lt;p&gt;其中一个典型场景是，HOT更新到了page外（容易测试）&lt;/p&gt;
&lt;p&gt;space reclamation happens during tuple retrieval when the
page is nearly full (&amp;lt;10% free) and a buffer cleanup lock can be
acquired. This means that UPDATE, DELETE, and SELECT can trigger space
reclamation, but often not during INSERT &amp;hellip; VALUES because it does
not retrieve a row.&lt;/p&gt;
&lt;p&gt;SELECT/UPDATE/DELETE扫描行的都可能发生空间回收动作，INSERT不会，因为INSERT不会扫描行。&lt;/p&gt;
&lt;p&gt;显然prune or defragment后对应的xid应该回收了，从readme就可以看出来通过HOT更新可以复现prune or defragment，然后产生CLEAN walrecord。见[测试：update产生页内修剪](## 测试：纯update产生页内修剪)&lt;/p&gt;

&lt;h2 class="relative group"&gt;测试
 &lt;div id="测试" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;以下测试只观察到冲突产生或者有CLEAN walrecord或者有页上lp的更新，不区分到底是prune还是defragment。很多场景应该是一起触发两者，区分两者有点费劲，maybe以后再说。这里主要是看CLEAN walrecord等有没有。&lt;/p&gt;
&lt;p&gt;会用到的sql：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--sql for test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--heap_page_items
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; t_ctid,lp,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; lp_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0:LP_UNUSED&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_NORMAL&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_REDIRECT&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_DEAD&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; lp_flags,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t_xmin,t_xmax,t_field3 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; t_cid, raw_flags, info.combined_flags,&lt;span style="color:#66d9ef"&gt;substring&lt;/span&gt;(t_data,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)) item,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2) info 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; lp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--heap header 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; page_header(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--bt_page_items
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, dead, htid, tids[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; some_tids &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bt_page_items(&lt;span style="color:#e6db74"&gt;&amp;#39;idxlzl&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--create table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl(a char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxlzl &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;md5(random()::text); &lt;span style="color:#75715e"&gt;--非hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--触发索引扫描
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_seqscan &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_indexonlyscan&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--开启rr事务获取快照不释放，方便观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ISOLATION&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LEVEL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPEATABLE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;READ&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;测试：异表查询冲突
 &lt;div id="测试异表查询冲突" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%bc%82%e8%a1%a8%e6%9f%a5%e8%af%a2%e5%86%b2%e7%aa%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;primary&lt;/th&gt;
 &lt;th&gt;standby&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;create table lzl(a bigint primary key);&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;insert into lzl values(1);&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;select 1;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;update lzl set a=2;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;不阻塞&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;vacuum lzl;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;#3 ResolveRecoveryConflictWithVirtualXIDs (waitlist=0x277c340, reason=reason@entry=PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, wait_event_info=wait_event_info@entry=134217762, report_waiting=report_waiting@entry=true) at standby.c:276&lt;br/&gt;#4 0x0000000000787b33 in ResolveRecoveryConflictWithVirtualXIDs (report_waiting=true, wait_event_info=134217762, reason=PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, waitlist=&lt;optimized out&gt;) at standby.c:333&lt;br/&gt;#5 ResolveRecoveryConflictWithSnapshot (latestRemovedXid=&lt;optimized out&gt;, node=&amp;hellip;) at standby.c:329&lt;br/&gt;#6 0x00000000004c8ffe in heap_xlog_clean (record=0x273a258) at heapam.c:7764&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;结论：只要查询产生，就会有快照，有快照就会有快照xmin，即使查询的表毫不相干，也可以发生查询冲突&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试：vacuum产生页内修剪
 &lt;div id="测试vacuum产生页内修剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95vacuum%e4%ba%a7%e7%94%9f%e9%a1%b5%e5%86%85%e4%bf%ae%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;会修剪，会冲突。示例略，跟本案无关&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试：update产生页内修剪
 &lt;div id="测试update产生页内修剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95update%e4%ba%a7%e7%94%9f%e9%a1%b5%e5%86%85%e4%bf%ae%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--HOT，更新到页外defragment
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--一个8k的heap page，存储的行数是4-2xx条。这里规划了行大小，生成4条数据保证HOT，下一条更新即触发页外更新
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl(a char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; idxlzl &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--heap page 4条数据，且HOT:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+----------+----------+-------+----------------------------------------------------------------------------------------------------------+----------------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954161&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954162&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_HOT_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954162&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954163&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_UPDATED,HEAP_HOT_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954163&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954164&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_UPDATED,HEAP_HOT_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954164&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--索引条目仅一个：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; itemoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; itemlen &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nulls &lt;span style="color:#f92672"&gt;|&lt;/span&gt; vars &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; htid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; some_tids 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+-------+---------+-------+------+------+-------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--再更新一条，触发页外更新
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--page已满，hot不了了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--hot链改变。lp改变
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-------------+----------+----------+--------+--------------------------------------------------------------------------------------+----------------+---------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_REDIRECT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954165&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:LP_UNUSED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954164&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954165&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_UPDATED,HEAP_HOT_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--索引条目仅一个，没变：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; itemoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; itemlen &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nulls &lt;span style="color:#f92672"&gt;|&lt;/span&gt; vars &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; htid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; some_tids 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+-------+---------+-------+------+------+-------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再次更新，row没有写到下个页，而是在本页发生页内修剪后写入本页，这样减少了一个页的访问。&lt;/p&gt;
&lt;p&gt;wal产生CLEAN remxid ，也说明可以发生查询冲突：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap2 len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 62/ 62, tx: 0, lsn: 3DB/F8017348, prev 3DB/F8017310, desc: CLEAN remxid 34954177, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/5893914/5893920 blk 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 2070/ 2070, tx: 34954178, lsn: 3DB/F8017388, prev 3DB/F8017348, desc: HOT_UPDATE off &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;34954178&lt;/span&gt; flags 0x10 ; new off &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/5893914/5893920 blk 0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;结论：update语句可产生页内修剪，可产生查询冲突&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试：hintbit回写产生页内修剪？
 &lt;div id="测试hintbit回写产生页内修剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95hintbit%e5%9b%9e%e5%86%99%e4%ba%a7%e7%94%9f%e9%a1%b5%e5%86%85%e4%bf%ae%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;primary&lt;/th&gt;
 &lt;th&gt;standby&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;wal_log_hints=on&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;truncate table lzl;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;insert into lzl values(&amp;lsquo;z&amp;rsquo;);&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;select * from lzl;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;delete from lzl where a=&amp;lsquo;z&amp;rsquo;;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;checkpoint;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;select * from lzl;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&amp;ndash;wal中生成FPI_FOR_HINT&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&amp;ndash;未发生查询冲突&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;standby的pageinspect：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;substring&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+----------+----------+-------+------------------------------------------------------------------------------+----------------+-------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954229&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954230&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_KEYS_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a202020202020202020202020202020202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;结论：wal log hint只是同步hintbit，不会对xmin/xmax产生影响，wal也不会有CLEAN等东西的产生，所以hintbit回写不会查询冲突。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试：查询产生页内修剪
 &lt;div id="测试查询产生页内修剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e6%9f%a5%e8%af%a2%e4%ba%a7%e7%94%9f%e9%a1%b5%e5%86%85%e4%bf%ae%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;查询正常不会修剪，但page被填满会：https://www.modb.pro/db/1683648157451362304&lt;/p&gt;
&lt;p&gt;填满page测试pruning：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--还是刚才的表，4条记录且HOT，几乎填满
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时的page：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+----------+----------+-------+----------------------------------------------------------------------------------------------------------+----------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954232&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954233&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_HOT_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954233&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954234&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_UPDATED,HEAP_HOT_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954234&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954235&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_UPDATED,HEAP_HOT_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954235&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- 一个查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时的page产生页内修剪
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sub
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-------------+----------+--------+--------+---------------------------------------------------------------------------------------+----------------+---------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_REDIRECT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:LP_UNUSED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:LP_UNUSED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34954235&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x501f00007a20202020202020202020202020&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;结论：查询可以产生页内修剪，可以产生查询冲突&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;测试：共享表多database查询冲突
 &lt;div id="测试共享表多database查询冲突" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b5%8b%e8%af%95%e5%85%b1%e4%ba%ab%e8%a1%a8%e5%a4%9adatabase%e6%9f%a5%e8%af%a2%e5%86%b2%e7%aa%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;共享表是global的，之前在&lt;code&gt;GetConflictingVirtualXIDs&lt;/code&gt;中有看到global的会无脑冲突。所以可以测一把。&lt;/p&gt;
&lt;p&gt;共享表信息如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;源码定义：&lt;/span&gt;IsSharedRelation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;源码判断：&lt;/span&gt;shared &lt;span style="color:#f92672"&gt;?&lt;/span&gt; InvalidOid : MyDatabaseId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;表：&lt;/span&gt;pg_class.relisshared
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;目录：&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;global&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;直接查&lt;code&gt;pg_class.relisshared&lt;/code&gt;要方便一点：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,relkind,relisshared &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relisshared &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; relkind&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relisshared 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------+---------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_authid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_subscription &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_database &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_db_role_setting &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_tablespace &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_auth_members &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_shdepend &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_shdescription &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_replication_origin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_shseclabel &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_authid会保存角色/用户的信息。这里以改密来测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--测试，在primary库 非业务db跑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; lzl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; password &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--多跑几次&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;产生CLEAN remxid：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;34954264&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D0F8, prev &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D0B8, &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;: HOT_UPDATE &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;67&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;34954264&lt;/span&gt; flags &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x20 ; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, blkref &lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;: rel &lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1260&lt;/span&gt; blk &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: &lt;span style="color:#66d9ef"&gt;Transaction&lt;/span&gt; len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;34954264&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D148, prev &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D0F8, &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;680782&lt;/span&gt; CST; inval msgs: catcache &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap2 len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D1A0, prev &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D148, &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;: CLEAN remxid &lt;span style="color:#ae81ff"&gt;34954264&lt;/span&gt;, blkref &lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;: rel &lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1260&lt;/span&gt; blk &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Heap2 len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;34954265&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;DB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;F808D1E0, &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;从库业务db的SQL&lt;code&gt;select 1&lt;/code&gt;被掐掉。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论：共享表可以发生跨db查询冲突。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不过这些共享表正常业务很难有大量更新。&lt;/p&gt;

&lt;h2 class="relative group"&gt;结论
 &lt;div id="结论" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%bb%93%e8%ae%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;开发视野
 &lt;div id="开发视野" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bc%80%e5%8f%91%e8%a7%86%e9%87%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;查询冲突可以跟查询的表无关，也就是说完全静态的表是可以发生冲突的。&lt;/p&gt;
&lt;p&gt;跨db意味着不同的业务和数据。跨db不会发生查询冲突。一个例外是共享表会，但是共享表只有几个系统表，一般不会有什么更新。&lt;/p&gt;
&lt;p&gt;对于开发来说，可以关注以下点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;请求重试&lt;/strong&gt;：从库的查询可能会被掐掉，重试查询是必要的，重试有可能会成功&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL时长&lt;/strong&gt;：SQL时间越长越容易被掐掉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他从库&lt;/strong&gt;：可能要选择其他容灾属性不高的从库&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;运维视野
 &lt;div id="运维视野" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%90%e7%bb%b4%e8%a7%86%e9%87%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为查询冲突可以从“四面八方”来，一个简单的长时间单表查询，可能会被其他频繁更新的表的页内修剪给干掉，所有可以调大&lt;code&gt;max_standby_streaming_delay&lt;/code&gt;以降低冲突的概率。&lt;/p&gt;
&lt;p&gt;但是，&lt;code&gt;max_standby_streaming_delay&lt;/code&gt;是以牺牲应用日志为代价的，相当于日志应用停止。这个参数的大小就代表了最大可能的从库复制延迟（限制不了网络延迟等其他因素造成的延迟）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;查询时效&lt;/strong&gt;：长时间的日志应用停止，从库的数据会严重落后（可能wal已经在从库磁盘上），会影响从库其他查询的数据时效要求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RTO&lt;/strong&gt;：如果主库灾难发生需要切换到从库，从库需要日志应用的时间。如果apply延迟太长比如几个小时，可能不能满足分钟级切换要求，这直接会影响SLA RTO承诺。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，调整&lt;code&gt;max_standby_streaming_delay&lt;/code&gt;是一个精细活，需要从从库的角色定义，查询时效要求，甚至地域等来综合考虑。&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL DDL变更的坑和巧妙方案</title><link>https://lastdba.com/2025/07/19/postgresql-ddl%E5%8F%98%E6%9B%B4%E7%9A%84%E5%9D%91%E5%92%8C%E5%B7%A7%E5%A6%99%E6%96%B9%E6%A1%88/</link><pubDate>Sat, 19 Jul 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/07/19/postgresql-ddl%E5%8F%98%E6%9B%B4%E7%9A%84%E5%9D%91%E5%92%8C%E5%B7%A7%E5%A6%99%E6%96%B9%E6%A1%88/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5f610ac9b703.png" alt="DDL变更.png" /&gt;&lt;/p&gt;
&lt;p&gt;自行保存，随便使用，不用问我&lt;/p&gt;
&lt;p&gt;可能更新，也可能不会更新&lt;/p&gt;
&lt;p&gt;欢迎交流，尽量挑刺&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5f610ac9b703.png" alt="DDL变更.png" /&gt;&lt;/p&gt;
&lt;p&gt;自行保存，随便使用，不用问我&lt;/p&gt;
&lt;p&gt;可能更新，也可能不会更新&lt;/p&gt;
&lt;p&gt;欢迎交流，尽量挑刺&lt;/p&gt;</content:encoded></item><item><title>Linux内存进阶</title><link>https://lastdba.com/2025/06/19/linux%E5%86%85%E5%AD%98%E8%BF%9B%E9%98%B6/</link><pubDate>Thu, 19 Jun 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/06/19/linux%E5%86%85%E5%AD%98%E8%BF%9B%E9%98%B6/</guid><description>&lt;p&gt;（内存基础知识参考 &lt;a href="https://blog.csdn.net/qq_40687433/article/details/135492312?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;linux内存浅析&lt;/a&gt;，本篇只有其上的内存知识）&lt;/p&gt;

&lt;h2 class="relative group"&gt;内存基本概念
 &lt;div id="内存基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;buddy
 &lt;div id="buddy" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#buddy" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;buddy系统申请和合并page的过程，略。&lt;/p&gt;</description><content:encoded>&lt;p&gt;（内存基础知识参考 &lt;a href="https://blog.csdn.net/qq_40687433/article/details/135492312?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;linux内存浅析&lt;/a&gt;，本篇只有其上的内存知识）&lt;/p&gt;

&lt;h2 class="relative group"&gt;内存基本概念
 &lt;div id="内存基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;buddy
 &lt;div id="buddy" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#buddy" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;buddy系统申请和合并page的过程，略。&lt;/p&gt;
&lt;p&gt;容易忽略的知识点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;buddy合并2个同大小块的前提它俩的&lt;strong&gt;物理地址连续&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;合并算法是迭代的，本级合并后会自行尝试合并更大的块。也就是说可以不依赖compactd来处理合并&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;page table &amp;amp; PTE
 &lt;div id="page-table--pte" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#page-table--pte" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;page table和PTE其实是两个不同的概念，十分容易混淆，因为他们总体还是在说页表。以下是page table和PTE的相关知识&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PTE存储了页框的物理地址&lt;/li&gt;
&lt;li&gt;“page table”和“Page Table”是不同的概念，“page table”指保持线性地址和物理地址之间映射的页，“Page Table”是上层页表中的页&lt;/li&gt;
&lt;li&gt;pte_t、pmd_t、pud_t、pgd_t 分别描述页表项、页中间目录项、页上级目录项、页全局目录项&lt;/li&gt;
&lt;li&gt;PTE是Page Table Entry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果只是看MMU缓存虚拟内存到物理内存映射区pagetable大小，把pagetable和PTE混淆差别不大；如果要深入到页表目录，需要将两个概念分开。&lt;/p&gt;

&lt;h3 class="relative group"&gt;TLB
 &lt;div id="tlb" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tlb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;每一级的页表是存储在内存里的，在完成一次虚拟内存地址转换的过程中，需要把当前虚拟地址对应的四个页表全部找出来，才能完成从虚拟地址到物理地址的转换。&lt;strong&gt;说明一次内存IO仅虚拟地址到物理地址的转换就要区内存查4次页表&lt;/strong&gt;。Translation Lookaside Buffers，就是专门用于加速虚拟地址到物理地址转换速度的缓存。&lt;/p&gt;
&lt;p&gt;关于TLB的位置，它通常位于L1缓存中（也有说在寄存器orL2的，应该跟cpu架构有关系，权且就当成cpu缓存，与主存区分）&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0a897b5be8a9.png" alt="image.png" /&gt;
在现代处理器中，L1缓存通常被划分为多个部分，包括数据缓存dTLB、指令缓存iTLB。频繁地修改页表会导致导致访问主存次数增加，这会使CPU频繁地刷新TLB缓存 &lt;sup id="fnref1:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。TLB也是有大小的，提升TLB的命中率可以减少对主存pagetable的访问。使用大页可以降低PTE三个数量级，TLB Miss会大大降低。&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;TLB的信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#cpuid -l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; L1 TLB/cache information: 2M/4M pages &amp;amp; L1 TLB &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x80000005/eax&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; L1 TLB/cache information: 4K pages &amp;amp; L1 TLB &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x80000005/ebx&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; L2 TLB/cache information: 2M/4M pages &amp;amp; L2 TLB &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x80000006/eax&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;观察TLB命中率:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses -I &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; -p $PM_PID &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在内存回收时，观察TLB missing确实会上涨，但难以形成因果关系，TLB missing只是观察MMU的一种观测指标，TLB is part of MMU。&lt;/p&gt;

&lt;h3 class="relative group"&gt;反向映射
 &lt;div id="反向映射" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%8d%e5%90%91%e6%98%a0%e5%b0%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PFRA（page fram reclaiming algorithm）页框回收算法总体原则&lt;sup id="fnref2:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先释放“无害”页。先回收pagecache上的无害页，这些页没有被任何进程占用&lt;/li&gt;
&lt;li&gt;用户态进程的所有页定位可回收页。FRPA将睡眠时间较长的用户态页可逐渐失去页框&lt;/li&gt;
&lt;li&gt;取消一个共享页框的所有页表项的映射，然后就可以回收该共享页框&lt;/li&gt;
&lt;li&gt;只回收“未用”页&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PFRA目标之一就是能释放共享页框，能快速定位指向同一页框的所有页表项的过程就叫反向映射（reverse mapping）。&lt;/p&gt;
&lt;p&gt;Reverse mappings for shared&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anonymous pages&lt;/li&gt;
&lt;li&gt;File-mapping pages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basic tricks of page frame reclaiming&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU lists&lt;/li&gt;
&lt;li&gt;Free cheapest pages first&lt;/li&gt;
&lt;li&gt;Unmap all at once&lt;/li&gt;
&lt;li&gt;Etc&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;大页
 &lt;div id="大页" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%a7%e9%a1%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;开启大页对特定应用的负载有一定提升。在pg中，大内存库开启大页也有一定的性能提升，甚至有一些稳定性的好处。&lt;/p&gt;
&lt;p&gt;为什么大页更好？[^ kernel.org, Page Table Management]：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;减少TLB的压力&lt;/li&gt;
&lt;li&gt;减少pagetable在主内存上的大小&lt;/li&gt;
&lt;li&gt;大页在物理上是连续的。连续的物理内存访问比不连续的物理内存访问更优&lt;/li&gt;
&lt;li&gt;When using these kinds of larger pages, higher level pages can directly map them, with no need to use lower level page entries[^ kernel.org,mm pagetables]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过使用大页会带来管理上的挑战：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要提前分配大页&lt;/li&gt;
&lt;li&gt;需要提前计算大页大小，以避免内存浪费&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;进程使用大页的两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first is by using &lt;code&gt;shmget()&lt;/code&gt; to setup a shared region backed by huge pages&lt;/li&gt;
&lt;li&gt;the second is the call &lt;code&gt;mmap()&lt;/code&gt; on a file opened in the huge page filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;C库和系统调用
 &lt;div id="c库和系统调用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#c%e5%ba%93%e5%92%8c%e7%b3%bb%e7%bb%9f%e8%b0%83%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;内核空间和用户空间之间的中间层就是系统调用层。应用编程接口（API)和系统调用是不同的。应用程序调用用户空间的实现的应用编程接口来编程，而不是直接执行系统调用。在UNIX的世界里，最通用的系统调用层是POSIX标准(Portable Operation System Interface of UNIX)。POSIX标准针对的是API而不是系统调用。Linux操作系统的API通常以C标准库方式提供，如libc库。C标准库提供了POSIX的绝大部分API的实现。&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;C app-&amp;gt;C lib-&amp;gt;system calls-&amp;gt;OS-&amp;gt;hardware&lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/72d91b350d7d.png" alt="image.png" /&gt;
常见C库和系统调用：&lt;/p&gt;
&lt;p&gt;malloc,free=&amp;gt;C lib&lt;/p&gt;
&lt;p&gt;mmap、brk、munmap=&amp;gt;系统调用&lt;/p&gt;

&lt;h3 class="relative group"&gt;缺页异常
 &lt;div id="缺页异常" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%bc%ba%e9%a1%b5%e5%bc%82%e5%b8%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;缺页异常（or缺页中断）需要区分两种情况：由编程错误所引起的异常；用虚拟地址空间但尚未分配物理页框所引起的分配物理页的行为。&lt;sup id="fnref3:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;异常的缺页：Segment Fault——每个虚拟内存区域具有相关权限。如果一个进程访问了不在有效范围内的内存区域，或者非法访问了内存区域，或者以不正确的方式访问了内存区域，那么处理器会报告缺页异常，严重的会报告“Segment Fault”段错误并终止进程&lt;sup id="fnref1:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;正常的缺页：mmap、brk等系统调用都是管理虚拟内存的，它们不直接分配物理内存。虚拟内存系统调用函数只建立进程地址空间，在用户空间里可以看到虚拟内存，但没有建立虚拟内存和物理内存直接的映射关系。当进程访问这些还没有建立映射关系的虚拟内存时，触发缺页中断。&lt;sup id="fnref2:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺页类型也分两种&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;minor fault：没有阻塞当前进程的情况下处理了缺页，分配了页框&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;major fault：缺页迫使当前进程睡眠（很可能是用磁盘上的数据填充页框花费时间），阻塞当前进程缺页就是主缺页major fault&lt;sup id="fnref4:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;写时复制COW
 &lt;div id="写时复制cow" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%99%e6%97%b6%e5%a4%8d%e5%88%b6cow" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;当执行fork系统调用时，子进程和父进程拥有独立的进程地址空间，但是共享物理内存资源，包括进程上下文、进程栈、内存信息、文件描述符、目录、资源限制等。只需要复制父进程中页表给子进程。此时以只读方式共享，当需要写入时（运行各自的任务时），数据才会被复制，使父进程和子进程拥有各自的副本。&lt;sup id="fnref3:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;对于PG多进程来说，fork本身不算重，可能只需要关心页表，但是fork之后到来的各种任务会发生写时复制创建子进程自己的资源副本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意区分写时复制和缺页异常：写时复制是说的fork时没有分配相应的资源给子进程；缺页异常是说的这个进程发生了物理内存分配，跟fork没有关系。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;mmap、brk&amp;amp;共享内存映射区、堆区
 &lt;div id="mmapbrk共享内存映射区堆区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mmapbrk%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98%e6%98%a0%e5%b0%84%e5%8c%ba%e5%a0%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;mmap、brk的功能和所使用的内存地址区域是不同的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mmap&lt;/code&gt; 用于管理共享内存，对应共享内存映射区&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;brk&lt;/code&gt; 用于管理私有内存，对应堆区&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;线性地址分区功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mmap ：映射区域至顶向下扩展，mmap 映射区域和堆相对扩展，直至耗尽虚拟地址空间中的剩余区域，这种结构便于C运行时库使用mmap 映射区域和堆进行内存分配。&lt;/li&gt;
&lt;li&gt;栈区(Stack)：存储程序执行期间的本地变量和函数的参数，从高地址向低地址生长&lt;/li&gt;
&lt;li&gt;堆区(Heap)：动态内存分配区域，通过 malloc、new、free 和delete 等函数管理&lt;/li&gt;
&lt;li&gt;未初始化变量区(BSS)：存储未被初始化的全局变量和静态变量&lt;/li&gt;
&lt;li&gt;数据区(Data)：存储在源代码中有预定义值的全局变量和静态变量&lt;/li&gt;
&lt;li&gt;代码区(Text)： 存储只读的程序执行代码，即机器指令。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;共享内存映射区和堆区&lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt; ：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/974eb641977f.png" alt="image.png" /&gt;
真实的postmaster的堆区和共享内存映射：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/1063005/smaps |grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;\-s|heap&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;022a4000-022ee000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;heap&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fef6019e000-7fef601a5000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:17 &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; /dev/shm/PostgreSQL.1291978332
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fef601a5000-7fef6098b000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:01 &lt;span style="color:#ae81ff"&gt;1052&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#75715e"&gt;#这是shared buffers的&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fef6e238000-7fef6e239000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:01 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; /SYSV0011f702 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到heap和共享内存区的地址差不多能对上。&lt;/p&gt;

&lt;h2 class="relative group"&gt;VM
 &lt;div id="vm" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vm" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;linux内核virtual memory子系统&lt;/p&gt;
&lt;p&gt;目录：&lt;code&gt;cd /proc/sys/vm/&lt;/code&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;compact
 &lt;div id="compact" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#compact" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;concept &amp;amp; param
 &lt;div id="concept--param" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#concept--param" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;内存压缩（Compaction）是Linux内核用于解决内存碎片化问题的机制，通过合并空闲物理页，提升大块内存页的分配和压缩效率。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数名&lt;/th&gt;
 &lt;th&gt;功能定位&lt;/th&gt;
 &lt;th&gt;默认值/范围&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;compact_memory&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;手动触发全局内存压缩操作&lt;/td&gt;
 &lt;td&gt;写入1触发&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;compaction_proactiveness&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;控制主动压缩的触发频率&lt;/td&gt;
 &lt;td&gt;4.x才有的参数。0-100（默认20）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;compact_unevictable_allowed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;是否允许压缩不可回收页（如&lt;code&gt;mlock&lt;/code&gt;锁定的内存）&lt;/td&gt;
 &lt;td&gt;4.x才有的参数。0（禁止）或1（允许）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;defrag_mode&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;控制内存碎片整理的触发策略&lt;/td&gt;
 &lt;td&gt;4.x才有的参数。0-3，0表示关闭自动compaction特性，只能手动压缩；1表示defer开启被动压缩。3.10默认1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;extfrag_threshold&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;大块内存不足时，触发压缩的阈值&lt;/td&gt;
 &lt;td&gt;0-1000（默认500）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;压缩有3种模式（跟内核版本是否支持相关）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;被动压缩：&lt;code&gt;extfrag_threshold&lt;/code&gt;是进程申请大块内存发现已经不足是否压缩，解决“已发生”的碎片问题。&lt;/li&gt;
&lt;li&gt;主动压缩：&lt;code&gt;compaction_proactiveness&lt;/code&gt;是主动控制压缩的积极性，优化“未发生”但可能出现的碎片风险。&lt;/li&gt;
&lt;li&gt;手动压缩：&lt;code&gt;compact_memory&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;extfrag_threshold&lt;/code&gt;是Linux内核中控制被动压缩的参数。当内核尝试分配高阶连续物理内存（如大页）失败时，会通过碎片化指数判断失败原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-1&lt;/code&gt;：分配成功（满足水位线）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;：因内存不足失败&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1000&lt;/code&gt;：因碎片化失败&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过&lt;code&gt;/sys/kernel/debug/extfrag/extfrag_index&lt;/code&gt;查看具体值，其输出为浮点数（如&lt;code&gt;0.854&lt;/code&gt;），但实际范围被放大1000倍，例如&lt;code&gt;0.854&lt;/code&gt;对应实际值854：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /sys/kernel/debug/extfrag/extfrag_index |grep Normal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.995 0.998 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;若extfrag_threshold=600，则当碎片化指数&amp;gt;600时触发压缩。extfrag_index还是挺有用的，可以协助buddy观察碎片问题。&lt;/p&gt;

&lt;h3 class="relative group"&gt;dirty
 &lt;div id="dirty" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dirty" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;concept &amp;amp; param
 &lt;div id="concept--param-1" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#concept--param-1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;刷脏跟内存回收有点类似，也分异步和同步：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异步刷脏：由pdflush/flush/kdmflush等后台线程执行，应用写入不受影响&lt;/li&gt;
&lt;li&gt;同步刷脏：直接阻塞应用进程，由发起写操作的进程自己刷脏&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数名称&lt;/th&gt;
 &lt;th&gt;作用描述&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_background_bytes&lt;/td&gt;
 &lt;td&gt;后台异步刷脏阈值，字节&lt;/td&gt;
 &lt;td&gt;0（未启用）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_background_ratio&lt;/td&gt;
 &lt;td&gt;后台异步刷脏阈值，百分比&lt;/td&gt;
 &lt;td&gt;10%&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_bytes&lt;/td&gt;
 &lt;td&gt;同步刷脏阈值，字节&lt;/td&gt;
 &lt;td&gt;0（未启用）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_ratio&lt;/td&gt;
 &lt;td&gt;同步刷脏阈值，百分比&lt;/td&gt;
 &lt;td&gt;20-40%&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_expire_centisecs&lt;/td&gt;
 &lt;td&gt;脏页在内存中的最长存活时间&lt;/td&gt;
 &lt;td&gt;3000（30秒）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;dirty_writeback_centisecs&lt;/td&gt;
 &lt;td&gt;内核周期性检查脏页状态的频率&lt;/td&gt;
 &lt;td&gt;500（5秒）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;xxx_bytes和xxx_ratio参数互斥。&lt;/p&gt;
&lt;p&gt;示例参数和流程图：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_background_bytes &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_background_ratio &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_bytes &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_ratio &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_expire_centisecs &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dirty_writeback_centisecs &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;%% 整合时间参数的刷脏流程图
graph TD
 A[应用程序写入生成脏页] --&amp;gt; B{检查周期到达?&amp;lt;br&amp;gt;dirty_writeback_centisecs 每5秒}
 B -- 否 --&amp;gt; D{存在超时脏页?&amp;lt;br&amp;gt; dirty_expire_centisecs&amp;gt;30秒}
 B -- 是 --&amp;gt; C{脏页阈值检查}
 C --&amp;gt; E[脏页占比? dirty_background_ratio&amp;gt;10% ]
 C --&amp;gt; F[脏页占比? dirty_ratio&amp;gt; 40%]
 E -- 触发 --&amp;gt; G[后台异步刷脏]
 F -- 触发 --&amp;gt; H[同步刷脏]
 D -- 触发 --&amp;gt; G
 G --&amp;gt; I[脏页写入磁盘]
 H --&amp;gt; I[脏页写入磁盘] 
 I --&amp;gt; J[释放内存空间]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;刷脏参数的设置跟pg刷脏参数的基本原理差不多，设置的过低刷脏过于频繁，同一个脏页可能多次写入磁盘浪费IO，过高可能会有IO风暴。&lt;/p&gt;

&lt;h4 class="relative group"&gt;观察脏页
 &lt;div id="观察脏页" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%a7%82%e5%af%9f%e8%84%8f%e9%a1%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;监控脏页&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps -eo pid,%cpu,%mem,wchan,args,state|grep kdmflush|grep -E -w -v &lt;span style="color:#e6db74"&gt;&amp;#34;S&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#观察异步刷脏进程状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/vmstat| grep -E -w &lt;span style="color:#e6db74"&gt;&amp;#34;nr_dirty|nr_writeback&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#vmstat dirty,页数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo |grep -i dirty &lt;span style="color:#75715e"&gt;#meminfo dirty，kb&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;使用dd测试脏页&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;nr_dirty_threshold|nr_dirty_background_threshold&amp;#34;&lt;/span&gt; /proc/vmstat | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{printf &amp;#34;%s: %.2fGB\n&amp;#34;, $1, ($2*4)/1048576}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nr_dirty_threshold: 141.28GB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nr_dirty_background_threshold: 35.32GB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dd &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/dev/zero of&lt;span style="color:#f92672"&gt;=&lt;/span&gt;testfile bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;8k count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;128000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# cache io &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;失败测试（测试多次仍然是这个结果）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未见RUNNING kdmflush进程&lt;/li&gt;
&lt;li&gt;没有满35GB，也没有满30S，脏页就被刷下去了&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;时间戳&lt;/th&gt;
 &lt;th&gt;nr_dirty&lt;/th&gt;
 &lt;th&gt;nr_dirty(GB)&lt;/th&gt;
 &lt;th&gt;趋势模拟&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;17:00:18&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;2,757&lt;/td&gt;
 &lt;td&gt;0.01052&lt;/td&gt;
 &lt;td&gt;▍&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:19&lt;/td&gt;
 &lt;td&gt;336,199&lt;/td&gt;
 &lt;td&gt;1.282&lt;/td&gt;
 &lt;td&gt;████▌&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:25&lt;/td&gt;
 &lt;td&gt;1,984,867&lt;/td&gt;
 &lt;td&gt;7.574&lt;/td&gt;
 &lt;td&gt;██████████████▍&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;17:00:32&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;4,252,177&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;16.22&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;████████████████████&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:33&lt;/td&gt;
 &lt;td&gt;3,699,227&lt;/td&gt;
 &lt;td&gt;14.11&lt;/td&gt;
 &lt;td&gt;█████████████████▊&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:38&lt;/td&gt;
 &lt;td&gt;170,865&lt;/td&gt;
 &lt;td&gt;0.652&lt;/td&gt;
 &lt;td&gt;▎&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:46&lt;/td&gt;
 &lt;td&gt;2,865,814&lt;/td&gt;
 &lt;td&gt;10.93&lt;/td&gt;
 &lt;td&gt;█████████▋&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;17:00:54&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;4,721,827&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;18.01&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;██████████████████████&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:00:55&lt;/td&gt;
 &lt;td&gt;3,876,509&lt;/td&gt;
 &lt;td&gt;14.79&lt;/td&gt;
 &lt;td&gt;██████████████████&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:01:03&lt;/td&gt;
 &lt;td&gt;835,097&lt;/td&gt;
 &lt;td&gt;3.186&lt;/td&gt;
 &lt;td&gt;██▊&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;os dirty !=pg dirty
 &lt;div id="os-dirty-pg-dirty" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#os-dirty-pg-dirty" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg fsync=on，数据写入是需要经过os pagecache然后再将指定块写入磁盘的。pg有自己的drity，os也有dirty，两者是什么关系？&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 观察语句&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo |grep -E -w &lt;span style="color:#e6db74"&gt;&amp;#34;Dirty&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# os脏页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; isdirty,pinning_backends,count&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*&lt;span style="color:#f92672"&gt;)&lt;/span&gt; from pg_buffercache where isdirty is true group by isdirty,pinning_backends; &lt;span style="color:#75715e"&gt;# pg脏页&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;checkpoint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;checkpoint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--观察&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;测试结果：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;stage&lt;/th&gt;
 &lt;th&gt;dirty in pg&lt;/th&gt;
 &lt;th&gt;os dirty&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;干净状态&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;0.02-2M 浮动&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;insert完成&lt;/td&gt;
 &lt;td&gt;200M&lt;/td&gt;
 &lt;td&gt;上涨到1.7G，随后降落到20KB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;commit提交&lt;/td&gt;
 &lt;td&gt;200M&lt;/td&gt;
 &lt;td&gt;0.02-2M 浮动&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;checkpoint刷脏&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;0.02-2M 浮动&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;将插入数据加大，insert时os dirty会上涨，涨到GB级再浮动。&lt;/p&gt;
&lt;p&gt;pg dirty跟os dirty有点关系但又不全是相关的，pg插入数据时 os dirty确实会上升，不过os自己刷脏后，pg的脏页仍然是脏页。初步判断共享内存中的脏页与os dirty无关，os dirty上涨暂未判断是不是pg私有内存的脏页。&lt;/p&gt;

&lt;h3 class="relative group"&gt;swappiness
 &lt;div id="swappiness" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#swappiness" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;控制系统从anonymous memory pool或 page cache 中回收内存的偏向性。其实是控制交换匿名页或者回收文件页，谁的代价对于上层应用来说更低。比如计算类的应用，动态分配或者私有内存使用更多，应该设置更低的swappiness，依赖数据的应用设置更高的swapiness以降低刷file page对数据访问的影响。不过这一切都建立在swap IO和filesystem IO的效率上&lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt;。一切都很美好，但是swap发生时很可能意味着性能降低。&lt;/p&gt;

&lt;h4 class="relative group"&gt;swappiness=0
 &lt;div id="swappiness0" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#swappiness0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;swappiness=0&lt;/code&gt;时，内核会直到内存到达high水位线时，才会做swap&lt;sup id="fnref:9"&gt;&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref"&gt;9&lt;/a&gt;&lt;/sup&gt;。具体的策略跟内核版本和NUMA也有关系。可以确认的是&lt;code&gt;swappiness=0&lt;/code&gt;不代表关闭了swap，&lt;code&gt;swapoff -a&lt;/code&gt;才是关闭swap功能。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查看是否打开了swap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;swapon --show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;free -h |grep Swap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/swaps
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;swap|none&amp;#39;&lt;/span&gt; /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo|grep Swap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#监控swapping是否发生&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/vmstat|grep swp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sar -W &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;inconsistent swap behavior
 &lt;div id="inconsistent-swap-behavior" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#inconsistent-swap-behavior" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;os层的 /proc/sys/vm/swappiness 对 cgroups v1 的系统的swap特性几乎没有影响（has little-to-no effect on the swap）。此问题可能导致不一致的swap行为&lt;sup id="fnref:10"&gt;&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref"&gt;10&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;发生场景（且）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vm.swappiness != cgroups memory.swappiness&lt;/li&gt;
&lt;li&gt;cgroups v1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发生原因：&lt;/p&gt;
&lt;p&gt;systemd在启动初期创建cgroups，早于&lt;code&gt;sysctl.service&lt;/code&gt;加载&lt;code&gt;/etc/sysctl.conf&lt;/code&gt; ，vm.swappiness 无法限制cgroup memory.swappiness。问题在于，当os的swap行为和cgroup不同时，到底哪个该生效的问题。&lt;/p&gt;
&lt;p&gt;解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for cgroup v1，设置vm.swappiness = all cgroups memory.swappiness&lt;/li&gt;
&lt;li&gt;for cgroup v1，很多解决办法，参考https://access.redhat.com/solutions/6785021&lt;/li&gt;
&lt;li&gt;使用cgroup v2。v2新增vm.force_cgroup_v2_swappiness参数，使cgroup的memory.swappiness失效&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;memory overcommitment
 &lt;div id="memory-overcommitment" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#memory-overcommitment" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;concept &amp;amp; param
 &lt;div id="concept--param-2" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#concept--param-2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;linux不是为每个虚拟地址预留物理内存，而是等到实际需要内存时才进行分配。overcommitment可以限制所有进程申请的总虚拟内存的大小，申请的内存超过限定的物理内存大小时，称为overcommit。&lt;/p&gt;
&lt;p&gt;overcommit策略参数有三个：&lt;code&gt;overcommit_memory&lt;/code&gt;，&lt;code&gt;overcommit_ratio&lt;/code&gt;/&lt;code&gt;overcommit_kbytes&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;overcommit_memory&lt;/code&gt;参数控制overcommitment策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;(默认): 启发式overcommitment策略，允许轻微的overcommit，CommitLimit=物理内存+swap 。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;: 无overcommit检查&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt;: 严格限制，禁止超过&lt;code&gt;CommitLimit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;graph TD
 A[内存分配请求] --&amp;gt; B{Overcommit模式}
 B --&amp;gt;|模式0:启发式| C[&amp;#34;允许适度超分虚拟内存&amp;#34;]
 B --&amp;gt;|模式1:无限制| D[&amp;#34;虚拟内存承诺无约束&amp;#34;]
 B --&amp;gt;|模式2:严格限制| E[&amp;#34;虚拟内存总量≤CommitLimit&amp;#34;]
 C --&amp;gt; F[运行时按需分配物理页]
 D --&amp;gt; G[可能耗尽物理内存+Swap]
 E --&amp;gt; H[强制虚拟内存总量控制]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;当&lt;code&gt;overcommit_memory=&lt;/code&gt;2时，&lt;code&gt;overcommit_ratio&lt;/code&gt;和&lt;code&gt;overcommit_kbytes&lt;/code&gt;参数只有一个会生效，此时的&lt;code&gt;CommitLlimit&lt;/code&gt;计算如下：
$$
CommitLimit = (RAM - 大页内存) × \frac{overcommit_ratio}{100} + SwapTotal
$$
or
$$
CommitLimit = (RAM - 大页内存) + overcommit_kbytes + SwapTotal
$$
有点意思的overcommit accounting&lt;sup id="fnref:11"&gt;&lt;a href="#fn:11" class="footnote-ref" role="doc-noteref"&gt;11&lt;/a&gt;&lt;/sup&gt;,mmap、brk、fork都计算在内，明显对pg是有影响的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We account mmap memory mappings
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We account mprotect changes in commit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We account mremap changes in size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We account brk
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We account munmap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	We report the commit status in /proc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	Account and check on fork
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	Review stack handling/building on exec
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	SHMfs accounting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;o	Implement actual limit enforcement&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;reserve内存和overcommmit
 &lt;div id="reserve内存和overcommmit" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#reserve%e5%86%85%e5%ad%98%e5%92%8covercommmit" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;user_reserve_kbytes&lt;/code&gt; ：在overcommit_memory=2时，为普通用户进程预留的物理内存，在系统内存严重不足时，确保普通用户仍能执行基本操作（如启动新进程、处理内存分配请求）。默认值为 min(3% of the current process size, 128M)。当设置为0时，单个进程可以分配（所有空闲内存-admin_reserve_kbytes）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;admin_reserve_kbytes&lt;/code&gt;：为具备 &lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt; 权限的用户（通常是 root 用户）保留的物理内存，确保管理员恢复能力，确保系统管理员可以登陆并执行命令的保留物理内存。默认min(3%内存, 8MB)。严格限制overcommit模式时最好提高该参数。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat user_reserve_kbytes 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;131072&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat admin_reserve_kbytes 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;观察overcommit
 &lt;div id="观察overcommit" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%a7%82%e5%af%9fovercommit" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;CommitLimit|Committed_AS&amp;#39;&lt;/span&gt; /proc/meminfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sar -r &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;CommitLimit|Committed_AS&amp;#39;&lt;/span&gt; /proc/meminfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CommitLimit: &lt;span style="color:#ae81ff"&gt;203103492&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Committed_AS: &lt;span style="color:#ae81ff"&gt;252170700&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sar -r &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;07:32:35 PM kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;07:32:37 PM &lt;span style="color:#ae81ff"&gt;25472180&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;370249056&lt;/span&gt; 93.56 &lt;span style="color:#ae81ff"&gt;14588&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;274485956&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;252242936&lt;/span&gt; 62.91 &lt;span style="color:#ae81ff"&gt;233866528&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;103568816&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12924&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;07:32:38 PM &lt;span style="color:#ae81ff"&gt;25471904&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;370249332&lt;/span&gt; 93.56 &lt;span style="color:#ae81ff"&gt;14588&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;274487888&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;252242740&lt;/span&gt; 62.91 &lt;span style="color:#ae81ff"&gt;233851748&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;103570136&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11180&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;观测指标含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meminfo CommitLimit：由物理内存、Swap及overcommit参数共同计算得出的CommitLimit&lt;/li&gt;
&lt;li&gt;meminfo Committed_AS：当前所有进程已申请的虚拟内存总量&lt;/li&gt;
&lt;li&gt;sar -r kbcommit = Committed_AS&lt;/li&gt;
&lt;li&gt;sar -r %commit =kbcommit/总物理内存&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;smaps或者status也可以查看总申请的虚拟内存，但直接算smaps/status的总计虚拟内存重复计算了共享库文件，映射文件（如mmap），而&lt;code&gt;Committed_AS&lt;/code&gt; 仅统计mmap、brk、fork等申请的内存，且不会重复计算共享内存。两者计算口径不同，看总虚拟内存还是看Committed_AS或者kbcommit就行。&lt;/p&gt;

&lt;h3 class="relative group"&gt;watermark
 &lt;div id="watermark" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#watermark" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数名称&lt;/th&gt;
 &lt;th&gt;作用描述&lt;/th&gt;
 &lt;th&gt;引入版本&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;th&gt;单位/范围&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;min_free_kbytes&lt;/td&gt;
 &lt;td&gt;定义系统保留的最小空闲内存量，直接影响内存水位 &lt;code&gt;watermark[min]&lt;/code&gt; 的计算，确保系统在内存紧张时保留足够内存供关键操作使用&lt;/td&gt;
 &lt;td&gt;早期内核版本&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;KB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;watermark_scale_factor&lt;/td&gt;
 &lt;td&gt;全局调节内存水位线间距（&lt;code&gt;high-low&lt;/code&gt; 和 &lt;code&gt;low-min&lt;/code&gt;）&lt;/td&gt;
 &lt;td&gt;Linux 内核4.x（4.几未知）&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;10&lt;/code&gt;（ 0.1%物理内存）&lt;/td&gt;
 &lt;td&gt;最大&lt;code&gt;3000&lt;/code&gt;（30%物理内存）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;watermark_boost_factor&lt;/td&gt;
 &lt;td&gt;临时提升内存高水位线（&lt;code&gt;high&lt;/code&gt;），触发积极内存回收以减少碎片化&lt;/td&gt;
 &lt;td&gt;Linux 内核4.x（4.几未知）&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;15000&lt;/code&gt;（即 1.5 倍原始高水位线）&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;min_free_kbytes
 &lt;div id="min_free_kbytes" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#min_free_kbytes" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 从zoneinfo中计算zone的总min等值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/zoneinfo | grep -E -w &lt;span style="color:#e6db74"&gt;&amp;#34;min|low|high&amp;#34;&lt;/span&gt;|grep -E -v &lt;span style="color:#e6db74"&gt;&amp;#34;high:&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/min/ { total_min += $2 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/low/ { total_low += $2 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/high/ { total_high += $2 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;END {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; printf &amp;#34;总min: %d KB\n总low: %d KB\n总high: %d KB\n&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; total_min * 4, total_low * 4, total_high * 4;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;总min: &lt;span style="color:#ae81ff"&gt;15828844&lt;/span&gt; KB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;总low: &lt;span style="color:#ae81ff"&gt;19786048&lt;/span&gt; KB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;总high: &lt;span style="color:#ae81ff"&gt;23743260&lt;/span&gt; KB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#当前系统min值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat min_free_kbytes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;15828849&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为有其他zone，所有zone的总min加起来才差不多min_free_kbytes。Normal zone的min肯定比min_free_kbytes小一点点，只需要关注Normal zone就行了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## Normal zone的min、low、high设置；page=4k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/zoneinfo | grep -A &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; Normal | grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;min|low|high&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; min &lt;span style="color:#ae81ff"&gt;3931615&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; low &lt;span style="color:#ae81ff"&gt;4914518&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; high &lt;span style="color:#ae81ff"&gt;5897422&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在Linux 内核4.6前，min、low、high是固定比例，只能通过设置min_free_kbytes来改变low、high的值，&lt;strong&gt;min：low：high=1：1.25：1.5&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;固定比例的问题：&lt;/p&gt;
&lt;p&gt;本身应该提高low积极触发kswapd异步回收，降低min减少direct reclaim。在4.6前只能通过调整min来间接调整low/high，通过调整min来调整kswapd的delta工作缓冲。例如&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;kswapd异步回收工作缓冲（low-min）&lt;/th&gt;
 &lt;th&gt;kswapd异步回收工作量（high-low）&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;min=1GB，low=1.25GB，high=1.5GB&lt;/td&gt;
 &lt;td&gt;0.25GB&lt;/td&gt;
 &lt;td&gt;0.25GB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;min=10GB，low=12.5GB，high=15GB&lt;/td&gt;
 &lt;td&gt;2.5GB&lt;/td&gt;
 &lt;td&gt;2.5GB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;提高min是为了提高low和high。&lt;/p&gt;
&lt;p&gt;过低的min值，会导致kswapd还没来得及异步回收更多的内存，direct reclaim就触发了。过高的min，不仅浪费了内存，也会导致内存回收动作更频繁，sys cpu会更多。Linux中默认的low与min之间的差值确实显得小了点。&lt;/p&gt;

&lt;h4 class="relative group"&gt;watermark_scale_factor
 &lt;div id="watermark_scale_factor" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#watermark_scale_factor" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;如果可以直接调整min、low、high不是美滋滋吗？抱歉，linux内核没有（安卓有extra_free_kbytes）。但是，&lt;/p&gt;
&lt;p&gt;linux4.x内核以后新增watermark_scale_factor参数可以调节参数之间的比例，比例不再是固定的了。其默认值为10，对应内存占比0.1%(10/10000)，最大为3000。当它的值被设定为1000时，意味着&amp;quot;low&amp;quot;与&amp;quot;min&amp;quot;之间的差值，以及&amp;quot;high&amp;quot;与&amp;quot;low&amp;quot;之间的差值都将是内存大小的10%(1000/10000)。&lt;/p&gt;
&lt;p&gt;0.1%明显是小了，1T的内存，scale才1GB。&lt;/p&gt;

&lt;h4 class="relative group"&gt;watermark_boost_factor
 &lt;div id="watermark_boost_factor" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#watermark_boost_factor" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;watermark_boost_factor 用于优化内存外碎片化。它临时提高内存管理区的水位，即 zone-&amp;gt;watermark_boost 从而提高内存管理区的高水位（ WMARK_HIGH），这样 kswapd 可以回收更多内存，内存规整模块（ compactd 内核线程）就比较容易合并大块的连续物理内存。 watermark_boost_factor 的默认值是 15000，表示会临时把原来的高水位提升到 150%。若把这个值设置为 0，则关闭临时提高内存管理区水位的机制&lt;sup id="fnref:12"&gt;&lt;a href="#fn:12" class="footnote-ref" role="doc-noteref"&gt;12&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;oom
 &lt;div id="oom" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#oom" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;OOM Killer 是内核模块不是一个进程。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数名称&lt;/th&gt;
 &lt;th&gt;作用描述&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;panic_on_oom&lt;/td&gt;
 &lt;td&gt;控制OOM发生时系统行为： &lt;strong&gt;0: 不触发panic，启动OOM Killer&lt;/strong&gt; 1: 触发panic并停机 2: 触发panic后尝试内存释放&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;oom_kill_allocating_task&lt;/td&gt;
 &lt;td&gt;是否优先杀死触发OOM的进程（而非遍历进程树选择最优目标）： 0: 禁用 1: 启用&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;oom_dump_tasks&lt;/td&gt;
 &lt;td&gt;OOM发生时是否转储所有任务信息（用于事后分析）： 0: 禁用 1: 启用&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;oom_score
 &lt;div id="oom_score" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#oom_score" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;oom发生时，系统需要通过oom score决定要kill哪个进程。 每个用户进程都有3个oom score接口文件&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- 1 postgres postgres 0 May 24 16:39 /proc/63766/oom_adj
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r--r--r-- 1 postgres postgres 0 May 24 16:39 /proc/63766/oom_score
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- 1 postgres postgres 0 May 24 16:39 /proc/63766/oom_score_adj&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;oom_score是系统自动计算的动态oom分数，至少受以下影响：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;很多子进程的 +分&lt;/li&gt;
&lt;li&gt;运行很长时间的 -分&lt;/li&gt;
&lt;li&gt;low nice value +分 (nice value代表进程的cpu时间片优先级。nice值越低，优先级越高，CPU时间片分配更多)&lt;/li&gt;
&lt;li&gt;直接访问硬件的 -分&lt;sup id="fnref:13"&gt;&lt;a href="#fn:13" class="footnote-ref" role="doc-noteref"&gt;13&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了linux自己算的oom分数，还可以自行调整（adj）oom分数。oom_adj是linux内核早期版本的，最好通过调整oom_score_adj接口文件来调整adj score。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数/文件&lt;/th&gt;
 &lt;th&gt;作用&lt;/th&gt;
 &lt;th&gt;示例值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;oom_score&lt;/td&gt;
 &lt;td&gt;内核计算的原始评分（动态变化）&lt;/td&gt;
 &lt;td&gt;0~1000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;oom_score_adj&lt;/td&gt;
 &lt;td&gt;用户自定义调整值，直接影响最终评分&lt;/td&gt;
 &lt;td&gt;-1000~1000；-1000等价于禁用OOM&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;oom_adj（旧版）&lt;/td&gt;
 &lt;td&gt;旧版调整参数，范围-17~15&lt;/td&gt;
 &lt;td&gt;-17~15&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 class="relative group"&gt;lowmem_reserve_ratio
 &lt;div id="lowmem_reserve_ratio" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lowmem_reserve_ratio" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;除了&lt;code&gt;min_free_kbytes&lt;/code&gt;，还有一个最低内存保留参数，会可能导致进程申请内存失败，但他们功能有较大差别。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lowmem_reserve_ratio&lt;/code&gt; 是一个用于保护低端内存（DMA、DMA32）不被高端内存分配请求过度占用键内核参数。lowmem_reserve_ratio只是一个系数，并不是直接可用的数，内核会计算每个zone的保留页数。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#下面默认值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/sys/vm/lowmem_reserve_ratio 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;256&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;内存区域（zone）按优先级从低到高排列：DMA → DMA32 → Normal → HighMem。高优先级区域的分配请求可“借用”低优先级区域的内存，但需按比例保留一定内存供低优先级区域使用。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/zoneinfo |grep -Ew &lt;span style="color:#e6db74"&gt;&amp;#34;Node 0|protection|free&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pages free &lt;span style="color:#ae81ff"&gt;3976&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; protection: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0, 2484, 386430, 386430&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA32
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pages free &lt;span style="color:#ae81ff"&gt;415741&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; protection: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0, 0, 383946, 383946&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pages free &lt;span style="color:#ae81ff"&gt;5658528&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; protection: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0, 0, 0, 0&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;例如DMA的 protection 表示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0:本区分配，没有跨区分配的限制&lt;/li&gt;
&lt;li&gt;2484：DMA为来自DMA32区域保留的页数。&lt;/li&gt;
&lt;li&gt;386430：DMA为来自Normal区域保留的页数&lt;/li&gt;
&lt;li&gt;386430：保留扩展字段，此场景中无意义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上设置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当DMA32区申请DMA区的内存时，3976&amp;gt;2484，是有可能成功的&lt;/li&gt;
&lt;li&gt;当Normal区申请DMA区的内存时，3976&amp;lt;386430，是不会成功的&lt;/li&gt;
&lt;li&gt;地区向高区申请内存，不会受到该限制&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;misc
 &lt;div id="misc" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#misc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;还有一丢丢相关的参数，关系不大的没有列举&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数&lt;/th&gt;
 &lt;th&gt;作用&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;nr_hugepages&lt;/td&gt;
 &lt;td&gt;大页数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;del&gt;nr_overcommit_hugepages&lt;/del&gt;&lt;/td&gt;
 &lt;td&gt;大页的overcommit；The maximum is nr_hugepages + nr_overcommit_hugepages&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;del&gt;nr_hugepages_mempolicy&lt;/del&gt;&lt;/td&gt;
 &lt;td&gt;NUMA本地化大页分配&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;del&gt;hugetlb_shm_group&lt;/del&gt;&lt;/td&gt;
 &lt;td&gt;共享内存权限控制&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;del&gt;hugetlb_optimize_vmemmap&lt;/del&gt;&lt;/td&gt;
 &lt;td&gt;重构大页元数据管理模型，减少大页元数据（struct page）的内存占用。linux 内核5.13开始支持&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_map_count&lt;/td&gt;
 &lt;td&gt;限制单个进程可拥有的内存映射区域（VMA）的最大数量，默认65530&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;zone_reclaim_mode&lt;/td&gt;
 &lt;td&gt;NUMA下内存回收策略，例如从其他节点分配内存&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;stat_interval&lt;/td&gt;
 &lt;td&gt;vm stat刷新频率，默认1秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;vfs_cache_pressure&lt;/td&gt;
 &lt;td&gt;虚拟文件系统（VFS）缓存回收压力的参数，主要影响内核回收dentry、inode缓存的积极性&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;page-cluster&lt;/td&gt;
 &lt;td&gt;swap readahead，一次交换多个page到swap分区。默认3，即一次8个pages&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 class="relative group"&gt;OS内存的观测和计算
 &lt;div id="os内存的观测和计算" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#os%e5%86%85%e5%ad%98%e7%9a%84%e8%a7%82%e6%b5%8b%e5%92%8c%e8%ae%a1%e7%ae%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;/proc/meminfo，/proc/vmstat，/proc/zoneinfo中都有内存信息，很多信息还是重复的。差异就不列举了没啥意思，看一眼就知道了。&lt;/p&gt;

&lt;h3 class="relative group"&gt;free available的计算（未完成）
 &lt;div id="free-available的计算未完成" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#free-available%e7%9a%84%e8%ae%a1%e7%ae%97%e6%9c%aa%e5%ae%8c%e6%88%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;大体方向：(NR_FREE_PAGES+NR_FILE_PAGES-NR_SHMEM+NR_SWAP_PAGES+NR_SLBA_RECLAIMABLE-TOTALRESERVE_PAGES-root预留内存)&lt;/p&gt;
&lt;p&gt;内核有估算可用内存，直接用公式计算available有点难计算出准确的值：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 不太准确，别用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo |grep -Ew &lt;span style="color:#e6db74"&gt;&amp;#34;MemFree|Active\(file\)|Inactive\(file\)|SwapFree|SReclaimable|nr_shmem|Shmem&amp;#34;&lt;/span&gt; |awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2} NR==4 {d=$2} NR==5 {e=$2} NR==6 {f=$2 ;print (a+b+c+d-e+f)}&amp;#39;&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo |grep -Ew &lt;span style="color:#e6db74"&gt;&amp;#34;MemAvailable&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;inactive_anon+active_anon != anon
 &lt;div id="inactive_anonactive_anon--anon" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#inactive_anonactive_anon--anon" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;why？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主要：Shmem 会单独统计共享内存的页数。nr_anon_pages 未包含共享内存页，而 nr_inactive_anon 和 nr_active_anon包含匿名共享内存页&lt;/li&gt;
&lt;li&gt;次要：anon包含部分Unevictable （Mlocked又是Unevictable的子集）&lt;/li&gt;
&lt;li&gt;其他统计口径差异影响不大&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;粗糙但比较准确的算法：nr_inactive_anon +nr_active_anon +nr_unevictable -nr_shmem&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 大页下适用；numa下不适用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## /proc/meminfo,/proc/zoneinfo,/proc/vmstat都可以计算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#/proc/vmstat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;anon_computed : &amp;#34;&lt;/span&gt;;cat /proc/vmstat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;nr_inactive_anon|nr_active_anon|nr_unevictable|nr_shmem&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2} NR==4 {d=$2; print (a+b+c-d)}&amp;#39;&lt;/span&gt; ;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;anon_real : &amp;#34;&lt;/span&gt;;cat /proc/vmstat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;nr_anon_pages&amp;#34;&lt;/span&gt;|awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_computed : &lt;span style="color:#ae81ff"&gt;15776924&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_real : &lt;span style="color:#ae81ff"&gt;15772671&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;##/proc/zoneinfo Normal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;anon_normal_computed : &amp;#34;&lt;/span&gt;; cat /proc/zoneinfo |grep Normal -A 50|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;nr_inactive_anon|nr_active_anon|nr_unevictable|nr_shmem&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2} NR==4 {d=$2; print (a+b+c-d)}&amp;#39;&lt;/span&gt; ;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;anon_normal_real : &amp;#34;&lt;/span&gt;; cat /proc/zoneinfo |grep Normal -A 50|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;nr_anon_pages&amp;#34;&lt;/span&gt;|awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_normal_computed : &lt;span style="color:#ae81ff"&gt;15711170&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_normal_real : &lt;span style="color:#ae81ff"&gt;15707402&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;cache的计算
 &lt;div id="cache的计算" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cache%e7%9a%84%e8%ae%a1%e7%ae%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;free命令中的buff/cache，可以通过文件页或者cache本身计算出来&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;filepage+shmem: &amp;#34;&lt;/span&gt;;cat /proc/meminfo |grep -Ew &lt;span style="color:#e6db74"&gt;&amp;#34;Buffers|Active\(file\)|Inactive\(file\)|Shmem|SReclaimable&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2} NR==4 {d=$2} NR==5 {e=$2 ;print (a+b+c+d+e)}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;cached: &amp;#34;&lt;/span&gt;;cat /proc/meminfo |grep -Ew &lt;span style="color:#e6db74"&gt;&amp;#34;Buffers|Cached|SReclaimable&amp;#34;&lt;/span&gt; | awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2 ;print (a+b+c)}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;free -k;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#执行结果：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;filepage+shmem: &lt;span style="color:#ae81ff"&gt;289417584&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cached: &lt;span style="color:#ae81ff"&gt;289419156&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total used free shared buff/cache available
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: &lt;span style="color:#ae81ff"&gt;395721236&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;79633516&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26668564&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;84704912&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;289419156&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;178501152&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: &lt;span style="color:#ae81ff"&gt;5242876&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5242876&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;争议：shmem算不算cache？
 &lt;div id="争议shmem算不算cache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%89%e8%ae%aeshmem%e7%ae%97%e4%b8%8d%e7%ae%97cache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;很明显，上面在计算cache的时候，把shmem也算进去了。shmem理论上应该不属于cache的部分&lt;/p&gt;
&lt;p&gt;实际上内核社区也讨论过这个事情&lt;a href="https://lore.kernel.org/all/YS0Eq&amp;#43;tNe4Pr7O0X@casper.infradead.org/T/" target="_blank" rel="noreferrer"&gt;Why is Shmem included in Cached in /proc/meminfo?&lt;/a&gt;，想把共享内存从cache中抛出去：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;	cached &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;global_node_page_state&lt;/span&gt;(NR_FILE_PAGES) &lt;span style="color:#f92672"&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;			&lt;span style="color:#a6e22e"&gt;total_swapcache_pages&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; i.bufferram;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt;	cached &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;global_node_page_state&lt;/span&gt;(NR_FILE_PAGES) &lt;span style="color:#f92672"&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt;			&lt;span style="color:#a6e22e"&gt;total_swapcache_pages&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt;			&lt;span style="color:#f92672"&gt;-&lt;/span&gt; i.bufferram &lt;span style="color:#f92672"&gt;-&lt;/span&gt; i.sharedram;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;但是修改这个东西涉及向前兼容，问题就归结于向前兼容和修改一个信息表达的准确性谁更重要？&lt;/p&gt;
&lt;p&gt;目前来看没有一个好的解决，反正现状就是这样了。&lt;/p&gt;
&lt;p&gt;这个邮件还讨论到一些有意思的东西：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Another point of view is that everything in tmpfs is part of the page
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cache and can be written out to swap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Dirty: total amount of RAM used to buffer data to be written on
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;permanent storage (dirty). Gets converted to Cached when write is
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;complete. (Actually I would call this &amp;#34;Buffers&amp;#34; but Dirty is okay, too.)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Cached: total amount of RAM used to improve *performance* that can be
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*immediately dropped* without any data-loss – note that this includes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;all untouched RAM backed by swap.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- Shared: total amount of RAM shared between multiple process that
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cannot be freed even if any single process gets killed. (If this is even
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;possible to know - note that this would *only* contain COW pages in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;practice. We already have Committed_AS which is about as good for real
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;world heuristics.)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;cache是不包含dirty的，可以直接drop不会造成数据丢失&lt;/li&gt;
&lt;li&gt;tmpfs是swapout&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;共享内存看上去是swapout，明显跟cache page可以直接drop的性质是不同的。pg的共享内存明显不可以直接drop。&lt;/p&gt;
&lt;p&gt;所以对于pg来说，cache有共享内存一点，还是很重要的，不要默认以为没有。&lt;/p&gt;

&lt;h3 class="relative group"&gt;内存页统计数据老对不上
 &lt;div id="内存页统计数据老对不上" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e9%a1%b5%e7%bb%9f%e8%ae%a1%e6%95%b0%e6%8d%ae%e8%80%81%e5%af%b9%e4%b8%8d%e4%b8%8a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;计算内存页的时候，有些计算对不上，汇总原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;shmem算到cache中&lt;/li&gt;
&lt;li&gt;看不到shmem中的文件映射和匿名映射pages&lt;/li&gt;
&lt;li&gt;nr_anon_pages 未包含共享内存页，而 nr_inactive_anon 和 nr_active_anon包含匿名共享内存页&lt;/li&gt;
&lt;li&gt;vm和cgroup的统计口径略有差别&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;cgroup v1
 &lt;div id="cgroup-v1" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cgroup-v1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;cgroup 内存管理
 &lt;div id="cgroup-内存管理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cgroup-%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;cgroup可以观察和限制匿名页，文件页，swap cache，kernel mem的使用情况。每个memcg都有独立的LRU，没有GLOBAL LRU的概念。&lt;/p&gt;
&lt;p&gt;cgroup内存管理不同于cgroup cpu管理，1个任务可以申请很多cpu工作，达到cg cpu上线可延长执行时间来处理，但是这个任务占用的内存是工作内存，一个任务使用相同的物理内存。&lt;/p&gt;
&lt;p&gt;cgroup管理cpu和内存的重要区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内存必须通过复用和回收来管理，一个任务的工作内存是真实占用的不可被其他任务使用的；CPU通过时间分配来管理，其他任务或cg组可以用到&lt;/li&gt;
&lt;li&gt;内存需要即时可用，CPU通过时间片轮转，时间可以分散&lt;/li&gt;
&lt;li&gt;CPU control的核心是时间分配；Memory Control的核心是page计数&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;The core of the design is a counter called the page_counter. The
page_counter tracks the current memory usage and limit of the group of
processes associated with the controller&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Memory Control的核心是page计数，也就是说不是物理page分这些就是这些，这次申请的内存使用完后释放回free，下次申请基本上不会是同一个物理page&lt;sup id="fnref:14"&gt;&lt;a href="#fn:14" class="footnote-ref" role="doc-noteref"&gt;14&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;物理page知道自己属于哪个cgroup：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				+--------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				| mem_cgroup |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				| &lt;span style="color:#f92672"&gt;(&lt;/span&gt;page_counter&lt;span style="color:#f92672"&gt;)&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				+--------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 / ^ &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				/ | &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------+ | +---------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | mm_struct | |.... | mm_struct |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------+ | +---------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; + --------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------+ +------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | page +----------&amp;gt; page_cgroup|
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------+ +---------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;mm_struct代表虚拟内存。每个虚拟内存都知道自己属于哪个cgroup；每个物理page都可以指向page_cgroup，即知道这个物理内存属于哪个cgroup&lt;sup id="fnref1:14"&gt;&lt;a href="#fn:14" class="footnote-ref" role="doc-noteref"&gt;14&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;cgroup 参数和指标
 &lt;div id="cgroup-参数和指标" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cgroup-%e5%8f%82%e6%95%b0%e5%92%8c%e6%8c%87%e6%a0%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;cgroup通过接口文件配置和查看内存使用情况。&lt;/p&gt;
&lt;p&gt;目录：&lt;code&gt;cd /sys/fs/cgroup/memory/xxx/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;内核内存和mem+swap可以单独设置或查看使用上限和使用情况：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;memory.kmem.xxx #kernel mem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;memory.memsw.xxx #mem+swap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以下只看mem相关的。&lt;/p&gt;
&lt;p&gt;接口文件可分为三类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只读-显示使用情况，权限:&lt;code&gt;-r--r--r--&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;读写-控制参数，权限:&lt;code&gt;-rw-r--r--&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;其他-特殊设置，权限:其他&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体含义如下，重要参数标出：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;type&lt;/th&gt;
 &lt;th&gt;接口文件&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;只读&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;memory.numa_stat&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;numa维度mem stat&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;只读&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;&lt;code&gt;memory.stat&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;重要&lt;/strong&gt;，是主要的内存使用情况接口文件，有很多指标，下面单独分析&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;只读&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;memory.usage_in_bytes&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;usage_in_bytes is affected by the method and doesn&amp;rsquo;t show &amp;rsquo;exact&amp;rsquo; value of memory。不建议使用该文件查看cgroup的内存使用情况&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;只读&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;&lt;code&gt;memory.failcnt&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;内存使用量超过&lt;code&gt;memory.limit_in_bytes&lt;/code&gt;的次数，累计值&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cgroup.clone_children&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;控制子 cgroup 是否继承父级配置&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;&lt;code&gt;cgroup.procs&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;用于管理当前 cgroup 中的 进程组（进程 ID，PID）。&lt;strong&gt;对于多进程的pg来说，就是把pg的所有进程，包括管理进程和backend都写入&lt;code&gt;procs&lt;/code&gt;文件&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tasks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;用于管理当前 cgroup 中的 线程（线程 ID，TID）。将进程 PID 写入 &lt;code&gt;cgroup.procs&lt;/code&gt; 时，其所有线程 TID 会自动添加到 &lt;code&gt;tasks&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;notify_on_release&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;控制当 cgroup 中的最后一个任务（进程或线程）退出时，是否触发释放操作。容器管理才有可能打开，传统的cgroup管理默认都是关闭，数据库重启cgroup还是要保留的&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;memory.move_charge_at_immigrate&lt;/td&gt;
 &lt;td&gt;v2已启用该参数。迁移croup时charge归属规则&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;memory.use_hierarchy&lt;/td&gt;
 &lt;td&gt;父cgroup是否限制子cgroup&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;memory.limit_in_bytes&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;cgroup内存上限&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;memory.soft_limit_in_bytes&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;内存超限时回收超限的部分&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;memory.max_usage_in_bytes&lt;/td&gt;
 &lt;td&gt;cgroup使用峰值，属于观察指标&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;memory.oom_control&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;oom_kill_disable 1&amp;ndash;禁用oom&lt;br/&gt;under_oom 0是否处于OOM状态&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;读写&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;memory.swappiness&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;cg级别的swappiness&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;其他&lt;/td&gt;
 &lt;td&gt;memory.force_empty&lt;/td&gt;
 &lt;td&gt;仅写入，写入 &lt;code&gt;0&lt;/code&gt; 强制释放cgroup所有内存&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;其他&lt;/td&gt;
 &lt;td&gt;cgroup.event_control&lt;/td&gt;
 &lt;td&gt;事件通知接口，监听内存压力事件，需编程实现。常与memory.pressure_level配合使用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;其他&lt;/td&gt;
 &lt;td&gt;memory.pressure_level&lt;/td&gt;
 &lt;td&gt;内存压力通知级别&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;通过一个pg实例来看memory.stat中各个指标的含义。&lt;/p&gt;
&lt;p&gt;这个pg实例配置为：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_memory_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mmap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_buffers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;64GB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clients 800个左右，running&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat memory.stat
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cache &lt;span style="color:#ae81ff"&gt;345587761152&lt;/span&gt; 						 &lt;span style="color:#75715e"&gt;#page cache！！！&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rss &lt;span style="color:#ae81ff"&gt;27332608&lt;/span&gt; &lt;span style="color:#75715e"&gt;#匿名和swap cache内存大小，注意，跟OS的进程rss不同，这里明显不包含PG的共享内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rss_huge &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;#of bytes of anonymous transparent hugepages，注意是匿名大页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mapped_file &lt;span style="color:#ae81ff"&gt;61491769344&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 文件共享内存大小，这里包含pg的共享内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;swap &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;# swap分区上的&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pgpgin &lt;span style="color:#ae81ff"&gt;389395357&lt;/span&gt; &lt;span style="color:#75715e"&gt;# rss+cache的charge pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pgpgout &lt;span style="color:#ae81ff"&gt;305016672&lt;/span&gt; &lt;span style="color:#75715e"&gt;# rss+cache的uncharge pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pgfault &lt;span style="color:#ae81ff"&gt;1954040341&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 略&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pgmajfault &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 略&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;inactive_anon &lt;span style="color:#ae81ff"&gt;165728256&lt;/span&gt; &lt;span style="color:#75715e"&gt;# anonymous and swap cache memory on inactive LRU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;active_anon &lt;span style="color:#ae81ff"&gt;61549518848&lt;/span&gt; &lt;span style="color:#75715e"&gt;# anonymous and swap cache memory on active LRU list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;inactive_file &lt;span style="color:#ae81ff"&gt;138240962560&lt;/span&gt; &lt;span style="color:#75715e"&gt;# file-backed on inactive LRU list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;active_file &lt;span style="color:#ae81ff"&gt;145658613760&lt;/span&gt; &lt;span style="color:#75715e"&gt;# file-backed memory on active LRU list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unevictable &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 无法回收的内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hierarchical_memory_limit &lt;span style="color:#ae81ff"&gt;408021893120&lt;/span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hierarchical_memsw_limit &lt;span style="color:#ae81ff"&gt;9223372036854771712&lt;/span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_xxx &lt;span style="color:#75715e"&gt;# hierarchical &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;粗略来看（不看swap）cache+rss=inactive_anon+active_anon+inactive_file+active_file。&lt;/p&gt;
&lt;p&gt;这上面的值还挺绕的，cache+rss跟[in]active_anon/file也难有直接对应关系，再加上mapped_file这个共享内存不知道该算到哪去，容易算晕。结合各种文档和测试，手搓脚本如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#cginfo_lzl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;shared_mem_mapped : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;mapped_file&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2 / 1024 / 1024 /1024 }&amp;#39;&lt;/span&gt; ;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;shared_mem_anon : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;rss|inactive_anon|active_anon&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2} NR==3 {c=$2; print (b + c -a)/1024/1024/1024}&amp;#39;&lt;/span&gt; ;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;pagecache : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;cache&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2 / 1024 / 1024 /1024 }&amp;#39;&lt;/span&gt; ;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;pagecache_cache-share : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;cache|mapped_file&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;NR==1 {a=$2} NR==2 {b=$2; print (a - b)/1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;file_total : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;inactive_file|active_file&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;anon_total : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;inactive_anon|active_anon&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;total_used_rss+map : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;rss|mapped_file&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;total_mem_file+rss+map : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;inactive_file|active_file|rss|mapped_file&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;total_mem_rss+cache : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;rss|cache&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;total_mem_anon+file : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;inactive_file|active_file|inactive_anon|active_anon&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;total_memsw : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.stat|egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;rss|cache|swap&amp;#34;&lt;/span&gt;| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum += $2} END {print sum /1024/1024/1024}&amp;#39;&lt;/span&gt;;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -n &lt;span style="color:#e6db74"&gt;&amp;#34;hard_limit : &amp;#34;&lt;/span&gt;;cat /sys/fs/cgroup/memory/$PGNAME/memory.limit_in_bytes| awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $1 / 1024 / 1024 /1024 }&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#shared_buffers=2GB的库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_mapped : 1.69063
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_anon : 1.69828
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache : 5.94717
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache_cache-share : 4.25654
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_cache : 4.24889
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_cache : 3.23096
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_used_rss+map : 3.2233
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_file+rss+map : 7.47219
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_rss+cache : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_anon+file : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_memsw : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hard_limit : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;cgroup rss和process rss的差异
 &lt;div id="cgroup-rss和process-rss的差异" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cgroup-rss%e5%92%8cprocess-rss%e7%9a%84%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#shared_buffers= 64GB,所有pg进程的rss排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps -eo pid,ppid,rss,args |grep &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat $PGDATA/postmaster.pid|head -1&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;|sort -k3 -rn
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97632&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61103720&lt;/span&gt; postgres: lzlinst: checkpointer 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97633&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;59045152&lt;/span&gt; postgres: lzlinst: background writer 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2322820&lt;/span&gt; /paic/postgres/base/11.3/bin/postgres -D /paic/pg6888/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97637&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;85116&lt;/span&gt; postgres: lzlinst: pgsentinel 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97697&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19620&lt;/span&gt; postgres: lzlinst: dbmgr users &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; idle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97634&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17932&lt;/span&gt; postgres: lzlinst: walwriter 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;250063&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14508&lt;/span&gt; postgres: lzlinst: dbmon postgres &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; idle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97636&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13220&lt;/span&gt; postgres: lzlinst: stats collector 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;248777&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11576&lt;/span&gt; postgres: lzlinst: dbmon postgres &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; idle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97635&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2980&lt;/span&gt; postgres: lzlinst: autovacuum launcher 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97638&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2376&lt;/span&gt; postgres: lzlinst: logical replication launcher 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;97630&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1592&lt;/span&gt; postgres: lzlinst: logger 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;250185&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;39130&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;972&lt;/span&gt; grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto &lt;span style="color:#ae81ff"&gt;97627&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一般来说，pg rss值最多的是checkpointer和bgwriter进程，因为rss代表的真实使用的内存，含共享内存部分，这2个要刷shared buffer脏页的进程占用最多。也有查数据过多的backend也可能rss值较高，不过一般是抽数或者全表扫的慢sql导致。&lt;/p&gt;
&lt;p&gt;postmaster为什么很少？因为postmaster本身不需要做太多shared_buffer的操作，它只需要把共享内存的虚拟地址开辟下来，fork给其他进程用即可。&lt;/p&gt;
&lt;p&gt;pm的子进程的共享内存地址是相同的，rss就不一定了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/97632/smaps |grep -A &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zero&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#checkpointer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b4fd87cf000-2b60a2143000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;15925397&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;70411728&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;61087812&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;31429895&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/97633/smaps |grep -A &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zero&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#bgwriter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b4fd87cf000-2b60a2143000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;15925397&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;70411728&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;59043388&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;29394787&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/97627/smaps |grep -A &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zero&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#postmaster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b4fd87cf000-2b60a2143000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;15925397&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;70411728&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;2318408&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;1741764&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以上checkpointer和bgwriter占用最多的rss，且rss中大部分是共享内存。它们两个进程几乎平分了整个真实使用的共享内存，postmaster反倒使用不多。pm及其fork的所有子进程的共享内存的虚拟地址是相同的。&lt;/p&gt;
&lt;p&gt;但是，cgroup中的rss只有几十MB，远小于进程的rss&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /sys/fs/cgroup/memory/lzlinst/memory.stat |egrep -w &lt;span style="color:#e6db74"&gt;&amp;#34;rss|mapped_file&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rss &lt;span style="color:#ae81ff"&gt;88997888&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mapped_file &lt;span style="color:#ae81ff"&gt;52963262464&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看出来，pg共享内存没有在cgroup stat rss的统计中。cgroup的rss没有计算file page以及shared file page。&lt;/p&gt;
&lt;p&gt;linux kernel&lt;sup id="fnref2:14"&gt;&lt;a href="#fn:14" class="footnote-ref" role="doc-noteref"&gt;14&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Only anonymous and swap cache memory is listed as part of ‘rss’ stat. This should not be confused with the true ‘resident set size’ or the amount of physical memory used by the cgroup.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;进程和cgroup内存统计差异&lt;sup id="fnref:15"&gt;&lt;a href="#fn:15" class="footnote-ref" role="doc-noteref"&gt;15&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;内存&lt;/th&gt;
 &lt;th style="text-align: left"&gt;单进程&lt;/th&gt;
 &lt;th style="text-align: left"&gt;进程&lt;code&gt;cgroup(memcg)&lt;/code&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;cache&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;无&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;PageCache&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;mapped_file&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;无&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;file_rss + shmem_rss&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;RSS&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;anon_rss + file_rss ＋ shmem_rss&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;code&gt;anon_rss&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于pg来说，stat中的rss不包含file map共享内存。pg官网把mmap描述为anonymous shared mem：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Possible values are &lt;code&gt;mmap&lt;/code&gt; (for anonymous shared memory allocated using &lt;code&gt;mmap&lt;/code&gt;), &lt;code&gt;sysv&lt;/code&gt; (for System V shared memory allocated via &lt;code&gt;shmget&lt;/code&gt;)&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;cg把pg mmap的内存算成mapped_file。&lt;/p&gt;
&lt;p&gt;观察sysv和大页的情况，pg的memory.stat相关指标总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stat中的rss不包含file map共享内存。观察来看，无论是mmap还是sysv，rss都不含pg的共享内存&lt;/li&gt;
&lt;li&gt;同理，rss_huge也不含file map共享大页内存。观察来看，即便开启大页，stat也不含pg的共享内存&lt;/li&gt;
&lt;li&gt;无大页时，pg的共享内存（mmap or sysv）均统计在memory.stat mapped_file下；有大页时，不在stat中的任何指标中，包括rss_huge&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;mapped_file到底在哪里？
 &lt;div id="mapped_file到底在哪里" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mapped_file%e5%88%b0%e5%ba%95%e5%9c%a8%e5%93%aa%e9%87%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2cf787e36cc8.png" alt="RHEL Memory Usage Patterns" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;mapped_file在cache中，也在inactive_anon+active_anon中&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mapped_file也可以是匿名的，mmap/sysv都算在这里&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#shared_buffers=2GB的库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_mapped : 1.69063
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_anon : 1.69828
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache : 5.94717
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache_cache-share : 4.25654
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_cache : 4.24889
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_cache : 3.23096
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_used_rss+map : 3.2233
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_file+rss+map : 7.47219
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_rss+cache : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_anon+file : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_memsw : 7.47984
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hard_limit : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;soft_limit_in_bytes
 &lt;div id="soft_limit_in_bytes" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#soft_limit_in_bytes" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;软限制（&lt;code&gt;memory.soft_limit_in_bytes&lt;/code&gt;）是 cgroup 内存管理中的一种非强制约束。当 cgroup 的内存使用量超过软限制时，系统不会立即强制回收内存，而是会在 &lt;strong&gt;全局内存压力较大时&lt;/strong&gt;（例如系统整体内存紧张）优先回收该 cgroup 的超额内存。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;触发条件&lt;/strong&gt;：全局内存压力（例如系统空闲内存不足）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调用路径&lt;/strong&gt;：&lt;code&gt;kswapd&lt;/code&gt; → &lt;code&gt;balance_pgdat&lt;/code&gt; → 检查 cgroup 软限制 → 触发回收。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回收目标&lt;/strong&gt;：优先回收超出软限制的 cgroup 的内存页面。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+-------------------+ 全局内存压力检测 +-------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| kswapd 线程 | ---------------------&amp;gt; | balance_pgdat |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+-------------------+ +-------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | 遍历内存区域并检查
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | 检查各 cgroup 的软限制使用情况 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | 对超限 cgroup 触发回收
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | 页面回收（LRU 链表扫描等） |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; +---------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;soft_limit_in_bytes机制很像high，v2的soft_limit_in_bytes已过期，新增min、low、high三个参数。&lt;/p&gt;

&lt;h3 class="relative group"&gt;超卖对pagecache的影响
 &lt;div id="超卖对pagecache的影响" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%b6%85%e5%8d%96%e5%af%b9pagecache%e7%9a%84%e5%bd%b1%e5%93%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;再说&lt;/p&gt;

&lt;h3 class="relative group"&gt;cg oom
 &lt;div id="cg-oom" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cg-oom" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;正常来说，sharedbuffer=1/4的cg mem，那么在不计算私有内存的情况下，pagecache最大可以到3/4的cg mem。一般来说，正常的业务私有内存占用不会很多，如果cg mem打满是可以从cg pagecache中回收内存的（是直接内存回收，aliOS做了异步后台回收：&lt;a href="https://help.aliyun.com/zh/alinux/user-guide/memcg-backend-asynchronous-reclaim?spm=a2c4g.11186623.0.0.562f42bammLZmK" target="_blank" rel="noreferrer"&gt;Memcg后台异步回收内存）&lt;/a&gt;。所以测试cg oom最好的办法是用占用很多私有内存的会话而不是加压。&lt;/p&gt;
&lt;p&gt;测试用例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#观察score&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r--r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; 16:39 /proc/63766/oom_score
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rss &lt;span style="color:#75715e"&gt;# 随便哪个命令啦&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 一个可以占用很多私有内存的sql，很多union all有很多plan node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -d lzldb -tX -c &lt;span style="color:#e6db74"&gt;&amp;#34;create table lzl1(col1 varchar(1));&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -tX -c &lt;span style="color:#e6db74"&gt;&amp;#34;\o sqltext.sql&amp;#34;&lt;/span&gt; -c &lt;span style="color:#e6db74"&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;SELECT &amp;#39;select col1 from lzl1&amp;#39; || &amp;#39; union all&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;FROM generate_series(1, 100000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;UNION ALL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;SELECT &amp;#39;select col1 from lzl1;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;FROM generate_series(1, 1);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#调整stack参数不然sql会被掐掉&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -d lzldb -c &lt;span style="color:#e6db74"&gt;&amp;#34;set max_stack_depth=1024000&amp;#34;&lt;/span&gt; -f sqltext.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;cg oom off:&lt;/p&gt;
&lt;p&gt;wchan有oom信息，甚至有oom score，但不会被OOM killer干掉&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## vm oom打开; 0:不触发panic，启动OOM Killer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/sys/vm/panic_on_oom 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## cg oom关闭;1:禁用oom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /sys/fs/cgroup/memory/$PGNAME/memory.oom_control
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oom_kill_disable &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;under_oom &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ps -eo user,ppid,pid,state,%cpu,%mem,stime,wchan:14,args,rss,vsz,sig_block |grep &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;head -1 $PGDATA/postmaster.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt; |grep -v grep 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;19005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;870&lt;/span&gt; D 0.0 0.0 10:54 mem_cgroup_oom postgres: pg3ymhp2: lzluser &lt;span style="color:#ae81ff"&gt;7216&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2807460&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000000000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;19005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3417&lt;/span&gt; S 0.0 0.0 10:55 pipe_wait postgres: pg3ymhp2: lzluser &lt;span style="color:#ae81ff"&gt;22944&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2808540&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000000000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;19005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13069&lt;/span&gt; D 0.0 0.0 11:10 mem_cgroup_oom postgres: pg3ymhp2: lzluser &lt;span style="color:#ae81ff"&gt;11944&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2808348&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000000000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;19005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13104&lt;/span&gt; D 0.0 0.0 11:10 mem_cgroup_oom postgres: pg3ymhp2: lzluser &lt;span style="color:#ae81ff"&gt;12224&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2808348&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000000000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;19005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14352&lt;/span&gt; D 0.0 0.0 11:10 mem_cgroup_oom postgres: pg3ymhp2: lzluser &lt;span style="color:#ae81ff"&gt;11680&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2808348&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000000000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /sys/fs/cgroup/memory/$PGNAME/memory.oom_control
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oom_kill_disable &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;under_oom &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/97994/oom_score
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_mapped : 2.00019
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shared_mem_anon : 2.0023
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache : 2.0023
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pagecache_cache-share : 0.00211334
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_cache : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anon_cache : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_used_rss+map : 7.99789
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_file+rss+map : 7.99789
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_rss+cache : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mem_anon+file : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_memsw : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hard_limit : &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;目前看来，PG的进程在分配不到内存的时候也有可能跑崩，例如walwriter跑奔溃会导致其他进程都崩溃。&lt;/p&gt;
&lt;p&gt;cg oom on：&lt;/p&gt;
&lt;p&gt;用户进程因为oom score高而被kill，发送的是kill -9，pg绝大部分进程奔溃，postmaster &lt;code&gt;reset_shared()&lt;/code&gt;后自动拉起其他进程。mesage和dmesg都有out of memory相关信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#cg oom打开&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oom_kill_disable &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg log:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2025-05-29 19:10:45.945 CST,,,198877,,6838374d.308dd,4,,2025-05-29 18:30:37 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;server process (PID 236413) was terminated by signal 9: Killed&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Failed process was running: select col1 from lzl1 union all
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;message:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;May 29 19:10:45 lzlhost kernel: Memory cgroup stats for /t1lzldb: cache:8392988KB rss:8384228KB rss_huge:0KB mapped_file:7458316KB swap:0KB inactive_anon:1310184KB active_anon:15467032KB inactive_file:0KB active_file:0KB unevictable:0KB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;May 29 19:10:45 lzlhost kernel: Memory cgroup out of memory: Kill process 236413 (postgres) score 497 or sacrifice child
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;dmesg:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[Thu May 29 18:26:27 2025] Memory cgroup stats for /t1lzldb: cache:8392988KB rss:8384228KB rss_huge:0KB mapped_file:7458316KB swap:0KB inactive_anon:1310184KB active_anon:15467032KB inactive_file:0KB active_file:0KB unevictable:0KB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[Thu May 29 18:26:27 2025] Memory cgroup out of memory: Kill process 236413 (postgres) score 497 or sacrifice child
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[Thu May 29 18:26:27 2025] Killed process 236413 (postgres) total-vm:18828736kB, anon-rss:8328252kB, file-rss:2328kB, shmem-rss:1832kB&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;cg oom on和off对于pg库管理上的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on，cg oom killer会kill oom score高的进程，一般来说是用户进程&lt;/li&gt;
&lt;li&gt;off，cg oom killer不会启动。pg进程会hang，当然也可能自己恢复，但pg的关键进程（如walwriter）可能因内存不足而跑崩，实例一样可能挂掉。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意这里说的cg oom，不是vm oom。系统级的vm oom由系统级的vm overcommit机制来判断。&lt;/p&gt;

&lt;h3 class="relative group"&gt;cg v1的问题
 &lt;div id="cg-v1的问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cg-v1%e7%9a%84%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;没有统计cg pagetable&lt;/li&gt;
&lt;li&gt;没有统计cg slab&lt;/li&gt;
&lt;li&gt;没有统计cg hugepage（hugepage是没有charge，还不是没有算进去）&lt;/li&gt;
&lt;li&gt;没有统计cg异步、同步回收pages&lt;/li&gt;
&lt;li&gt;cg rss与process rss统计口径不统一&lt;/li&gt;
&lt;li&gt;shmem统计口径比较乱&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;what&amp;rsquo; new in V2
 &lt;div id="what-new-in-v2" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#what-new-in-v2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;V2 Officially released in Linux 4.5 (March 2016)&lt;sup id="fnref:16"&gt;&lt;a href="#fn:16" class="footnote-ref" role="doc-noteref"&gt;16&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;cgroup v2内存管理的提升和改变：&lt;sup id="fnref:17"&gt;&lt;a href="#fn:17" class="footnote-ref" role="doc-noteref"&gt;17&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;cg mem接口文件&lt;/th&gt;
 &lt;th&gt;对比v1&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.current&lt;/td&gt;
 &lt;td&gt;重修&lt;/td&gt;
 &lt;td&gt;当前使用内存大小。移除没什么用的usage_in_bytes&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.min&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;跟vm的min/low/high不同&lt;/strong&gt;。vm的水位线是操作系统剩的内存，cg v2的水位线是cg mem使用的内存。memory.min为硬保护内存保护值，默认值为0。系统没有可回收内存的时候，也不会回收在该值边界及以下的内存&lt;sup id="fnref:18"&gt;&lt;a href="#fn:18" class="footnote-ref" role="doc-noteref"&gt;18&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.low&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;尽力而为的内存保护值，默认值为0。系统优先回收未被保护的cgroup组的内存。如果内存还不足，再回收memory.min到memory.low之间的内存。&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.high&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;内存回收警示值，默认为max。当cgroup组内存使用量达到high值，会触发对该cgroup及子节点的同步内存回收任务，将内存尽量限制在high之下&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.max&lt;/td&gt;
 &lt;td&gt;重修&lt;/td&gt;
 &lt;td&gt;等价memory.limit_in_bytes&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;memory.reclaim&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;重修&lt;/td&gt;
 &lt;td&gt;主动回收接口文件，v1只有memory.force_empty强制清空&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.peak&lt;/td&gt;
 &lt;td&gt;重修&lt;/td&gt;
 &lt;td&gt;等价max_usage_in_bytes；超过peak会触发cg oom killer&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;memory.oom.group&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;控制 cg OOM killer时是否终止整个 cgroup（1）或仅单个进程（0）。默认为0.如果oom_score_adj=-1000，不会被kill&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.events&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;报告内存相关事件&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;memory.stat&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;重修&lt;/td&gt;
 &lt;td&gt;改变较多，单独分析&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;memory.zswap.current，memory.zswap.max，memory.zswap.writeback&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;td&gt;Zswap 是 Linux 内核中的一种&lt;strong&gt;内存压缩交换机制&lt;/strong&gt;，通过压缩待交换的内存页，减少对磁盘的 I/O 操作，从而提升系统性能。其核心思想是将原本需要写入磁盘的交换数据压缩后暂存于内存中，仅在必要时才将数据写入物理交换设备（如 Swap 分区或文件）&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;soft_limit_in_bytes&lt;/td&gt;
 &lt;td&gt;移除&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;memory.oom_control&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;移除&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;代表v2无法直接关闭cg oom killer&lt;/strong&gt;；不过可以通过设置min/low/high和设置event内存事件通知等来精细化管理内存&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;v2 cg mem在管理上有如下优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相对v1，v2有更简单明了的层级管理&lt;/li&gt;
&lt;li&gt;v1只有OOM kill or freeze，v2有更多手段控制内存大小(如memory.min/low/high)&lt;/li&gt;
&lt;li&gt;v2更容易控制突刺负载&lt;sup id="fnref:19"&gt;&lt;a href="#fn:19" class="footnote-ref" role="doc-noteref"&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;移除直接关闭cg oom killer的接口文件&lt;/li&gt;
&lt;li&gt;增加memory_hugetlb_accounting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;memory.stat：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;含义&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;v1 对应项&lt;/strong&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;anon&lt;/td&gt;
 &lt;td&gt;匿名页&lt;/td&gt;
 &lt;td&gt;active_anon+inactive_anon&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;file&lt;/td&gt;
 &lt;td&gt;文件页，含 tmpfs&lt;/td&gt;
 &lt;td&gt;active_file+inactive_file&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;kernel (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;总内核内存，包括kernel_stack, &lt;strong&gt;pagetables&lt;/strong&gt;, percpu, vmalloc, &lt;strong&gt;slab&lt;/strong&gt;以及其他内核内存的使用情况。&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;kernel_stack&lt;/td&gt;
 &lt;td&gt;kernel stacks占用的内存量。&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;pagetables&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;page tables&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sec_pagetables&lt;/td&gt;
 &lt;td&gt;二级页表，适合虚拟机、GPU 设备、网络加速卡等硬件资源隔离场景&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;percpu (npn)&lt;/td&gt;
 &lt;td&gt;存储per-cpu内核数据结构的内存大小&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sock (npn)&lt;/td&gt;
 &lt;td&gt;network transmission buffers&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;vmalloc (npn)&lt;/td&gt;
 &lt;td&gt;vmalloc&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;shmem&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;b包括tmpfs, shm , shared anonymous mmap&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;zswap&lt;/td&gt;
 &lt;td&gt;zswap压缩本身消耗的内存&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;zswapped&lt;/td&gt;
 &lt;td&gt;zswap了多少用户内存&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;file_mapped&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;mmap()大小&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;有点类似v1 mapped_file，不过mapped_file包含tmpfs、shm&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;file_dirty&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;同v1 dirty&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;file_writeback&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;同v1 writeback&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;swapcached&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;同v1 swapcached&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;anon_thp&lt;/td&gt;
 &lt;td&gt;透明大页中的匿名页&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;file_thp&lt;/td&gt;
 &lt;td&gt;透明大页中的文件页&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;shmem_thp&lt;/td&gt;
 &lt;td&gt;透明大页的shm、tpfs、匿名mmap&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;inactive_anon, active_anon, inactive_file, active_file, unevictable&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;同v1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;slab_reclaimable&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;slab_unreclaimable&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;slab (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;workingset_refault_anon，workingset_refault_file，workingset_activate_anon，workingset_activate_file，workingset_restore_anon，workingset_restore_file，workingset_nodereclaim&lt;/td&gt;
 &lt;td&gt;refaulted相关page统计&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pswpin (npn)&lt;/td&gt;
 &lt;td&gt;swap in&lt;/td&gt;
 &lt;td&gt;同v1 pgpgin&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pswpout (npn)&lt;/td&gt;
 &lt;td&gt;swap out&lt;/td&gt;
 &lt;td&gt;同v1 pgpgout&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgscan (npn)&lt;/td&gt;
 &lt;td&gt;scanned pages (in an inactive LRU list)&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgsteal (npn)&lt;/td&gt;
 &lt;td&gt;回收的内存&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;pgscan_kswapd (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;pgscan_direct (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgscan_khugepaged (npn)&lt;/td&gt;
 &lt;td&gt;透明大页守护进程扫描的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;pgscan_proactive (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;proactive主动扫描的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgsteal_kswapd (npn)，pgsteal_direct (npn)，pgsteal_khugepaged (npn)，pgsteal_proactive (npn)&lt;/td&gt;
 &lt;td&gt;意如其名，pgsteal*对应pgscan*&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgfault (npn)&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;同v1 pgfault&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgmajfault (npn)&lt;/td&gt;
 &lt;td&gt;意如其名&lt;/td&gt;
 &lt;td&gt;同v1 pgmajfault&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgrefill (npn)&lt;/td&gt;
 &lt;td&gt;在active LRU中扫描的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;pgactivate (npn)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;移动到active LRU中的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgdeactivate (npn)&lt;/td&gt;
 &lt;td&gt;移动到inactive LRU中的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pglazyfree (npn)&lt;/td&gt;
 &lt;td&gt;有内存压力时，推迟释放的pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pglazyfreed (npn)&lt;/td&gt;
 &lt;td&gt;已回收的lazyfree pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;swpin_zero,swpout_zero&lt;/td&gt;
 &lt;td&gt;zero-filled pages；在Swap In 阶段，内核检测到页面内容全为零（Zero-filled），标记该页为“零页”并记录在元数据中，跳过磁盘 I/O 操作&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;zswpin,zswpout,zswpwb&lt;/td&gt;
 &lt;td&gt;zswap相关pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;thp_fault_alloc (npn)，thp_collapse_alloc (npn)，thp_swpout (npn)，thp_swpout_fallback (npn)&lt;/td&gt;
 &lt;td&gt;透明大页相关pages&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;numa_pages_migrated (npn)，numa_pte_updates (npn)，numa_hint_faults (npn)&lt;/td&gt;
 &lt;td&gt;numa相关pages，其实还有memory.numa_stat&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pgdemote_kswapd，pgdemote_direct，pgdemote_khugepaged，pgdemote_proactive&lt;/td&gt;
 &lt;td&gt;没懂demote&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;hugetlb&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;大页&lt;/td&gt;
 &lt;td&gt;新增&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;v2 cg mem在观测上有如下优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增slab、pagetable、pgscank/pgsand/pgsteal、大页信息，这些都是v1没有的&lt;/li&gt;
&lt;li&gt;更多具体特性相关的观测指标，比如sock 、vmalloc、透明大页、zswap压缩交互、swap_zero全零交互等&lt;/li&gt;
&lt;li&gt;共享内存shmem和file_mapped指标分开&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;wchan
 &lt;div id="wchan" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#wchan" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Waiting Channel，name of the kernel function in which the process is sleeping&lt;/p&gt;
&lt;p&gt;一般来说要检查D状态的进程的wchan，看看进程在等待什么内核函数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-&lt;/code&gt;：Running tasks will display a dash (&amp;rsquo;-&amp;rsquo;) in this column&lt;/p&gt;
&lt;p&gt;&lt;code&gt;poll_schedule_timeout&lt;/code&gt;: PM常见，-一般在运行状态&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zz ***Fri May &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 04:50:10 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;141378&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.5 0.4 &lt;span style="color:#ae81ff"&gt;70585180&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2322876&lt;/span&gt; poll_schedule_timeout S 21:06:18 00:02:40 /paic/postgres/base/11.3/bin/postgres -D /paic/pg6888/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Fri May &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 04:50:43 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;141378&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.5 0.4 &lt;span style="color:#ae81ff"&gt;70585180&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2322876&lt;/span&gt; - R 21:06:18 00:02:42 /paic/postgres/base/11.3/bin/postgres -D /paic/pg6888/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;futex_wait_queue_me&lt;/code&gt;: SLEEP进程常见。偶现D&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;455358&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;141378&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 4.7 1.0 &lt;span style="color:#ae81ff"&gt;70590684&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5349576&lt;/span&gt; futex_wait_queue_me S 03:01:12 00:02:47 postgres: t1lzldb: lzl test3 30.181.32.3&lt;span style="color:#f92672"&gt;(&lt;/span&gt;39801&lt;span style="color:#f92672"&gt;)&lt;/span&gt; COMMIT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;hugetlb_fault&lt;/code&gt;：只见过hugepage刚加载，刚起负载时&lt;/p&gt;
&lt;p&gt;&lt;code&gt;do_last&lt;/code&gt;：虚拟文件系统（VFS）路径解析逻辑中的函数，负责处理文件路径的最后一个分量（如文件名或符号链接），并触发实际的文件操作&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lock_page_killable&lt;/code&gt;： 以可中断方式锁定物理内存页；可中断性是说允许进程在等待页面锁时响应致命信号，如&lt;code&gt;SIGKILL&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rpc_wait_bit_killable&lt;/code&gt;：该函数与远程过程调用（RPC）机制相关，用于在内核中等待某个位标志的变更&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wait_on_page_bit&lt;/code&gt;：等待页面标志位的状态变更（如PG_locked、PG_writeback）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blkdev_issue_flush&lt;/code&gt;：块设备层的刷新缓存函数；可能的调用链：用户调用&lt;code&gt;fsync()&lt;/code&gt; → 文件系统（如ext4）将相关脏页提交至块设备层 → 调用&lt;code&gt;blkdev_issue_flush()&lt;/code&gt;确保设备缓存刷新&lt;/p&gt;
&lt;p&gt;&lt;code&gt;on_proc_exit&lt;/code&gt;：注册进程退出时的清理函数&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ima_file_check&lt;/code&gt;：属于IMA（Integrity Measurement Architecture）子系统，用于在文件访问时验证其完整性；典型的有&lt;code&gt;open()&lt;/code&gt;调用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;flush_work&lt;/code&gt;：等待任务完成&lt;/p&gt;
&lt;p&gt;&lt;code&gt;call_rwsem_down_write_failed&lt;/code&gt;：当尝试获取写锁（&lt;code&gt;down_write()&lt;/code&gt;）失败时，此函数处理写锁竞争与等待逻辑。它通过自旋或睡眠机制让当前进程等待锁释放（&lt;code&gt;rwsem&lt;/code&gt;（读写信号量））&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get_request&lt;/code&gt; ：&lt;strong&gt;iowait高时出现&lt;/strong&gt;；从块设备请求队列中获取空闲的请求结构体（&lt;code&gt;struct request&lt;/code&gt;）。若队列已满（设备处理速度不足），线程将等待直至有可用请求&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lookup_slow&lt;/code&gt;：VFS（虚拟文件系统）路径解析的慢速路径&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * lookup_fast - do fast lockless (but racy) lookup of a dentry
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @nd: current nameidata
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Do a fast, but racy lookup in the dcache for the given dentry, and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * revalidate it. Returns a valid dentry pointer or NULL if one wasn&amp;#39;t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * found. On error, an ERR_PTR will be returned.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lookup_fast&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; nameidata &lt;span style="color:#f92672"&gt;*&lt;/span&gt;nd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* Fast lookup failed, do it the slow way */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__lookup_slow&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; qstr &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;dir,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flags)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lookup_slow&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; qstr &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;dir,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flags)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; inode &lt;span style="color:#f92672"&gt;*&lt;/span&gt;inode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dir&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_inode;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; dentry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;res;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;inode_lock_shared&lt;/span&gt;(inode);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__lookup_slow&lt;/span&gt;(name, dir, flags);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;inode_unlock_shared&lt;/span&gt;(inode);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; res;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;lookup_fast和lookup_slow都是在找dentry并返回dentry，lookup_fast会在dentry cache中寻找，如果失败会通过lookup_slow查找。&lt;/p&gt;
&lt;p&gt;开大页压测，无直接内存回收，出现以下事件：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lock_page&lt;/code&gt;：&lt;strong&gt;iowait高时出现&lt;/strong&gt;；内核尝试锁定一个内存页时，若页面已被其他线程/进程锁定，当前线程会进入等待状态。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vx_svar_sleep_unlock&lt;/code&gt;，&lt;code&gt;vx_ilock&lt;/code&gt;，&lt;code&gt;vx_bc_biowait&lt;/code&gt;，&lt;code&gt;vx_dio_physio&lt;/code&gt;，&lt;code&gt;vx_rwsleep_lock&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;vx是Veritas 公司开发的日志型&lt;strong&gt;文件系统&lt;/strong&gt;（现归属于 Symantec 及后续拆分后的 Veritas Technologies），设计目标为 高性能、高可用性的大规模数据存储，&lt;strong&gt;主要面向企业级应用场景&lt;/strong&gt;。跟xfs、ext4一样是一种文件系统。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pipe_wait&lt;/code&gt;：当进程尝试从管道（Pipe）读取数据或向管道写入数据时，若管道缓冲区已满（写操作）或已空（读操作），当前线程会进入休眠状态，等待缓冲区状态变化&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pipe_write&lt;/code&gt;：管道写操作的入口函数，当缓冲区满时，线程在此函数中休眠，等待可写空间&lt;/p&gt;
&lt;p&gt;&lt;code&gt;congestion_wait&lt;/code&gt;：当块设备 I/O 队列拥塞时（如请求队列已满或设备处理延迟），内核通过此函数让线程短暂休眠&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wait_iff_congested&lt;/code&gt;：检查块设备队列是否拥塞，若拥塞则进入短暂休眠。与 &lt;code&gt;congestion_wait&lt;/code&gt; 类似，但更轻量级，通常用于内存回收或脏页回写路径&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mem_cgroup_oom_synchronize&lt;/code&gt;：&lt;code&gt;usage_in_bytes&lt;/code&gt;达到&lt;code&gt;limit_in_bytes&lt;/code&gt;时，标记oom_control.under_oom=1，是否启用OOM killer内核模块取决于oom_control.oom_kill_disable&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mem_cgroup_oom&lt;/code&gt;:同&lt;code&gt;mem_cgroup_oom_synchronize&lt;/code&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;rmap_walk
 &lt;div id="rmap_walk" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rmap_walk" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PFRA目标之一是为了回收共享页框，为了达到这个目的，Linux 2.6内核能够快速定位指向同一页框的所有页表项，这个过程叫反向映射（reverse mapping）&lt;sup id="fnref5:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;当已被一个进程引用的页框插入另一个进程的页表项（fork）时，应该也会发生rmap_walk&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zcat hostlzl_ps_25.04.08.0900.dat.gz|egrep &lt;span style="color:#e6db74"&gt;&amp;#34;\-D /dirlzl/pg5998/data|zzz&amp;#34;&lt;/span&gt;|less
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Tue Apr &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 09:10:50 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.2 0.5 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117844&lt;/span&gt; poll_schedule_timeout S 22:17:21 00:01:56 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Tue Apr &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 09:11:20 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.2 0.5 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117844&lt;/span&gt; poll_schedule_timeout S 22:17:21 00:01:56 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Tue Apr &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 09:13:08 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.2 0.5 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117844&lt;/span&gt; - D 22:17:21 00:01:57 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;225076&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 1.6 0.0 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1720&lt;/span&gt; rmap_walk D 09:11:51 00:00:01 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;224924&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.7 0.0 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt; rmap_walk D 09:11:46 00:00:00 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;224817&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.5 0.0 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1720&lt;/span&gt; try_to_unmap_file D 09:11:44 00:00:00 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Tue Apr &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 09:19:16 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.3 0.5 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117884&lt;/span&gt; poll_schedule_timeout S 22:17:21 00:02:00 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;250875&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2208&lt;/span&gt; - R 09:19:17 00:00:00 /dirlzl/postgres/base/postgressqlbin/postgresdb -D /dirlzl/pg5998/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zzz ***Tue Apr &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 09:19:48 CST &lt;span style="color:#ae81ff"&gt;2025&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;209987&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0.3 0.5 &lt;span style="color:#ae81ff"&gt;70247548&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117884&lt;/span&gt; poll_schedule_timeout S 22:17:21 00:02:01 /dirlzl/postgres/base/postgressql/bin/postgresdb -D /dirlzl/pg5998/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;try_to_unmap_file
 &lt;div id="try_to_unmap_file" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#try_to_unmap_file" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;try_to_unmap_file()函数调用try_to_unmap_cluster()，而try_to_unmap_cluster()函数会扫描该线性区线性地址所对应的所有页表项，并尝试将他们清理&lt;sup id="fnref6:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。try_to_unmap_file()执行映射页的反向映射。注意，反向映射即通过pagetable反向寻找所有vma，并将共享物理页框回收。&lt;/p&gt;

&lt;h3 class="relative group"&gt;page_referenced
 &lt;div id="page_referenced" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#page_referenced" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;refenced和active用于控制page的活跃度，在页面回收中使用。refcount=0时表示空闲或即将要被释放的页面&lt;sup id="fnref4:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;在kernel.org doc的Object-Based Reverse Mapping中有对page_referenced()函数的描述[^ kernel.org, Page Table Management]：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;page_referenced()&lt;/code&gt; which checks all PTEs that map a page to see if the page has been referenced recently&lt;/p&gt;
&lt;p&gt;&lt;code&gt;page_referenced()&lt;/code&gt; calls &lt;code&gt;page_referenced_obj()&lt;/code&gt; which is the top level function for finding all PTEs within VMAs that map the page.&lt;/p&gt;
&lt;p&gt;If a page is mapped and it is referenced through the mapping, index hash table, this bit is set. It is used during page replacement for moving the page around the LRU lists&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;简言之，page_referenced()通过页框找到map的所有PTEs上的VMAs。这也是一个rmap的过程。&lt;/p&gt;
&lt;p&gt;Linux 引入了两个页面标志符 &lt;code&gt;PG_active&lt;/code&gt; 和 &lt;code&gt;PG_referenced&lt;/code&gt; 用于标识页面的活跃程度，从而决定如何在两个链表（active LRU和inactive LRU）之间移动页面。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4fd31681c3a0.png" alt="pic" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PG_active&lt;/code&gt; 用于表示页面当前是否是活跃的，如果该位被置位，则表示该页面是活跃的。&lt;code&gt;PG_referenced&lt;/code&gt; 用于表示页面最近是否被访问过，每次页面被访问，该位都会被置位。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;page_referenced()&lt;/code&gt;：&lt;strong&gt;当操作系统进行页面回收时&lt;/strong&gt;，每扫描到一个页面，就会调用该函数设置页面的 &lt;code&gt;PG_referenced&lt;/code&gt; 位。如果一个页面的 &lt;code&gt;PG_referenced&lt;/code&gt; 位被置位，但是在一定时间内该页面没有被再次访问，那么该页面的 &lt;code&gt;PG_referenced&lt;/code&gt; 位会被清除。&lt;sup id="fnref:20"&gt;&lt;a href="#fn:20" class="footnote-ref" role="doc-noteref"&gt;20&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;

&lt;h2 class="relative group"&gt;内存观察指标
 &lt;div id="内存观察指标" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e8%a7%82%e5%af%9f%e6%8c%87%e6%a0%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;查看基本内存设置：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7c22bffd37cf.png" alt="image.png" /&gt;
观察内存指标：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4fed9a1d93d7.png" alt="image.png" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;一些问题
 &lt;div id="一些问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%80%e4%ba%9b%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;kswapd和直接内存回收是否会一起执行？
 &lt;div id="kswapd和直接内存回收是否会一起执行" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#kswapd%e5%92%8c%e7%9b%b4%e6%8e%a5%e5%86%85%e5%ad%98%e5%9b%9e%e6%94%b6%e6%98%af%e5%90%a6%e4%bc%9a%e4%b8%80%e8%b5%b7%e6%89%a7%e8%a1%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;会。如果是水位线触发的内存回收，有pgscand时经常伴随pgscank，反之则不然。如果pgscank、pgscand均频繁，那么可以考虑调整内存回收水位线，调大delta，防止delta被快速冲破。&lt;/p&gt;
&lt;p&gt;不过还有一种情况，碎片率较高的时候，free还有很多，也有可能直接触发阻塞式内存压缩，有pgscand，完全没有pgscank。此时调整水位线就没有什么用了，可以考虑开启大页内存并提升一定的sharedbuffer命中率，减少pagecache频繁分配切碎内存。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pagetable过大对内存回收的影响
 &lt;div id="pagetable过大对内存回收的影响" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pagetable%e8%bf%87%e5%a4%a7%e5%af%b9%e5%86%85%e5%ad%98%e5%9b%9e%e6%94%b6%e7%9a%84%e5%bd%b1%e5%93%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pagetable过大，会增加反向映射的代价和时间。在直接内存回收时需要通过反向映射，找到所有进程的虚拟地址空间VMA，然后取消所有进程的VMA页表映射。也就说进程数越多，pagetable越大，内存回收也就越慢。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;postgres的进程数越多，pagetable越大；shared buffer越大，pagetable也越大。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;开启大页内存可以减少500倍（4k=&amp;gt;2M）pagetable大小，不仅可以空出一定内存，也可以提升内存回收效率。&lt;/p&gt;

&lt;h3 class="relative group"&gt;shared buffers多大合适
 &lt;div id="shared-buffers多大合适" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shared-buffers%e5%a4%9a%e5%a4%a7%e5%90%88%e9%80%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;sharedbuffers=1/4 cgmem 似乎以成为行业标准，但是实际情况要复杂的多。理论上，把sharedbuffers调小可以增加一点pagecache，实际上略微增大了整个缓存大小，把sharedbuffers调大略微减少了减少了整个缓存大小，但是提升了一定的sharedbuffer命中率。很明显，sharedbuffers调大了不好，调小了也不好。sharedbuffers调太小，pg自己能工作的内存就太小了，相当于把内存管理工作扔给了OS，OS回收pagecache时对性能也会有影响；sharedbuffers调太大，不仅pagecache被挤占，还需要考虑pg刷脏的影响，特别是写入较多的情况需要调整相应的bgwriter参数。&lt;/p&gt;
&lt;p&gt;从粗糙的压测来看&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不开大页，shared buffers=min(1/4 MEM,20GB)&lt;/li&gt;
&lt;li&gt;开大页，shared buffers=min(1/4 MEM,60GB)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;进程和线程的差别真的不大吗？
 &lt;div id="进程和线程的差别真的不大吗" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%9b%e7%a8%8b%e5%92%8c%e7%ba%bf%e7%a8%8b%e7%9a%84%e5%b7%ae%e5%88%ab%e7%9c%9f%e7%9a%84%e4%b8%8d%e5%a4%a7%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在任何linux内核资料中，都会说进程和线程的差别不大。无论是创建进程还是线程，内核中都是用同一个函数kernel_clone来实现的，唯一区别在于传入的参数不同，fork和clone的系统调用差不多&lt;sup id="fnref1:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fdb4c651f034.png" alt="image.png" /&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;strong&gt;维度&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;进程&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;线程&lt;/strong&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;childID&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;每个进程都有独立的 &lt;code&gt;pid&lt;/code&gt;（进程 ID）&lt;/td&gt;
 &lt;td&gt;每个线程有 &lt;code&gt;tid&lt;/code&gt;（线程 ID），但线程的 pid&lt;code&gt;与所属进程的&lt;/code&gt;pid` 一致。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;地址空间&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;每个进程拥有独立的地址空间（&lt;code&gt;mm_struct&lt;/code&gt;），包括内存、堆栈等。&lt;/td&gt;
 &lt;td&gt;线程共享所属进程的地址空间，所有线程的 &lt;code&gt;mm_struct&lt;/code&gt; 指向同一个地址空间。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;文件系统&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;每个进程有自己的 &lt;code&gt;fs_struct&lt;/code&gt;，包含文件描述符、挂载点等。&lt;/td&gt;
 &lt;td&gt;线程共享所属进程的 &lt;code&gt;fs_struct&lt;/code&gt;，所有线程的文件描述符和挂载点与进程一致。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;线程跟进程相比，只是稍微“轻量”了一点，总体来说进程和线程的相同点大于他们的不同点。&lt;/p&gt;
&lt;p&gt;但是，进程多了以后区别可就大了，特别是像pg这样的多进程应用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个进程都有自己的VMA，所以要维护更多的地址空间&lt;/li&gt;
&lt;li&gt;每个进程都有自己的pagetable，所以pagetable要占用更多的内存&lt;/li&gt;
&lt;li&gt;多进程会增加TLB的刷新负担，而线程不会&lt;/li&gt;
&lt;li&gt;进程切换需要更多的上下文开销，而线程不会&lt;/li&gt;
&lt;li&gt;进程间通信IPC效率更低，而线程直接共享内存不会有IPC通信问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以这么说，&lt;strong&gt;进程和线程在创建的时候差别不大，但是多进程管理和多线程管理差别很大&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么从库会有pg层脏页？
 &lt;div id="为什么从库会有pg层脏页" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bb%8e%e5%ba%93%e4%bc%9a%e6%9c%89pg%e5%b1%82%e8%84%8f%e9%a1%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;从库日志回放机制本身会产生脏页，从库也会刷脏。可通过pg_buffercache查看从库脏页，从库的脏页跟主库不一样，从库脏数据也是一般的relation；同时可以观察到从库的checkpoint/bgwriter/backend刷脏都跟主库不一样。&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么file cache有些库高有些低
 &lt;div id="为什么file-cache有些库高有些低" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88file-cache%e6%9c%89%e4%ba%9b%e5%ba%93%e9%ab%98%e6%9c%89%e4%ba%9b%e4%bd%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一般来说是离散度多的库file cache比较多，简单的慢sql是比较难把file cache长期维持在较高水平的。一个慢sql访问较多数据，可能会短暂的升高filecache，但是过一会这些file page的reference下降，并成为inactive file pages后，内存可以回收这一部分内存。但是频繁的离散度，比如索引的correlation接近0，如UUID主键，其SQL性能较好但reads高，可能产生频繁物理IO，加载了太多的page到filecache中。甚至业务模型的转变会导致shared buffer的大量换入换出，对性能影响较大。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg进程和共享内存映射
 &lt;div id="pg进程和共享内存映射" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e8%bf%9b%e7%a8%8b%e5%92%8c%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98%e6%98%a0%e5%b0%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#未开大页时，是/dev/zero （deleted）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/102208/smaps |egrep &lt;span style="color:#e6db74"&gt;&amp;#34;rw\-s&amp;#34;&lt;/span&gt; -A &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2aefd8901000-2aefd8902000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;1202061313&lt;/span&gt; /SYSV00001000 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2aefd8918000-2aefd898f000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:13 &lt;span style="color:#ae81ff"&gt;4084862058&lt;/span&gt; /dev/shm/PostgreSQL.1008001451
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;476&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2aefe2605000-2b00ad129000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;4084864418&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#开启大页时，是/anon_hugepage (deleted)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/29091/smaps |egrep &lt;span style="color:#e6db74"&gt;&amp;#34;rw\-s&amp;#34;&lt;/span&gt; -A &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2aaaaac00000-2ac3a2c00000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:0e &lt;span style="color:#ae81ff"&gt;215471503&lt;/span&gt; /anon_hugepage &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;104726528&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b48dfe93000-2b48dfe94000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;88604727&lt;/span&gt; /SYSV00001000 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b48dfeab000-2b48dff22000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:12 &lt;span style="color:#ae81ff"&gt;215515747&lt;/span&gt; /dev/shm/PostgreSQL.1123685558
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;476&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;子进程页表都是从父进程中复制过来的，父子进程因此共享同一页框&lt;sup id="fnref7:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。所以无论是postmaster还是backend进程（任何postmaster fork出来的进程），在虚拟内存地址中都会映射相同的共享内存地址，他们在smaps中的地址和Size是相等的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么pg的所有的进程的虚拟内存都是/dev/zero段占用多
 &lt;div id="为什么pg的所有的进程的虚拟内存都是devzero段占用多" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88pg%e7%9a%84%e6%89%80%e6%9c%89%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%9a%84%e8%99%9a%e6%8b%9f%e5%86%85%e5%ad%98%e9%83%bd%e6%98%afdevzero%e6%ae%b5%e5%8d%a0%e7%94%a8%e5%a4%9a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;mmap实现匿名页映射主要有两种方式：一种是通过设置&lt;code&gt;MAP_ANONYMOUS&lt;/code&gt;标志并传入&lt;code&gt;fd=-1&lt;/code&gt;，另一种是打开&lt;code&gt;/dev/zero&lt;/code&gt;设备文件并将得到的文件描述符传递给&lt;code&gt;mmap&lt;/code&gt;。这两种方法在功能上是等效的。&lt;/p&gt;
&lt;p&gt;pg sharebuffer使用的/dev/zero设备映射来实现的匿名共享页，所以一般能看到pg进程的/dev/zero的虚拟内存地址占用是比较多。&lt;/p&gt;

&lt;h2 class="relative group"&gt;References
 &lt;div id="references" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;[《深入理解Linux内核》]: 《深入理解Linux内核》： 内存寻址、内存管理、地址空间管理、回收页框&lt;/p&gt;
&lt;p&gt;[《深入理解Linux进程和内存》]: 《深入理解Linux进程和内存》 CPU硬件原理、进程、线程的对比&lt;/p&gt;
&lt;p&gt;[《奔跑吧 Linux内核 入门篇（第2版）》]: 《奔跑吧Linux内核入门篇（第2版）》 系统调用、内存管理&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;《深入理解Linux内核》：内存寻址、内存管理、地址空间管理、回收页框&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref2:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref3:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref4:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref5:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref6:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref7:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="https://www.cs.oslomet.no/~haugerud/os/Forelesning/os7.pdf" target="_blank" rel="noreferrer"&gt;https://www.cs.oslomet.no/~haugerud/os/Forelesning/os7.pdf&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;《深入理解Linux进程和内存》CPU硬件原理、进程、线程的对比&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;a href="https://www.cs.unc.edu/~porter/courses/comp630/s24/slides/pfra.pdf" target="_blank" rel="noreferrer"&gt;https://www.cs.unc.edu/~porter/courses/comp630/s24/slides/pfra.pdf&lt;/a&gt;&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;《奔跑吧Linux内核入门篇（第2版）》系统调用、内存管理&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref2:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref3:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref4:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;&lt;a href="https://courses.cs.washington.edu/courses/cse333/20wi/lectures/07/CSE333-L07-posix_20wi.pdf" target="_blank" rel="noreferrer"&gt;https://courses.cs.washington.edu/courses/cse333/20wi/lectures/07/CSE333-L07-posix_20wi.pdf&lt;/a&gt;&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;&lt;a href="https://www.sohu.com/a/392831824_467784" target="_blank" rel="noreferrer"&gt;https://www.sohu.com/a/392831824_467784&lt;/a&gt;&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/monitoring_and_managing_system_status_and_performance/configuring-an-operating-system-to-optimize-memory-access_monitoring-and-managing-system-status-and-performance#overview-of-a-systems-memory_configuring-an-operating-system-to-optimize-memory-access" target="_blank" rel="noreferrer"&gt;redhat,Configuringanoperatingsystemtooptimizememoryaccess&lt;/a&gt;&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/sysctl/vm.html#swappiness" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/html/latest/admin-guide/sysctl/vm.html#swappiness&lt;/a&gt;&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;&lt;a href="https://access.redhat.com/solutions/6785021" target="_blank" rel="noreferrer"&gt;https://access.redhat.com/solutions/6785021&lt;/a&gt;&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:11"&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/Documentation/vm/overcommit-accounting" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/Documentation/vm/overcommit-accounting&lt;/a&gt;&amp;#160;&lt;a href="#fnref:11" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:12"&gt;
&lt;p&gt;&lt;a href="https://carlyleliu.github.io/LinuxKernel/LinuxMemoryOptimization/" target="_blank" rel="noreferrer"&gt;https://carlyleliu.github.io/LinuxKernel/LinuxMemoryOptimization/&lt;/a&gt;&amp;#160;&lt;a href="#fnref:12" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:13"&gt;
&lt;p&gt;&lt;a href="https://www.man7.org/linux/man-pages/man5/proc_pid_oom_score.5.html" target="_blank" rel="noreferrer"&gt;https://www.man7.org/linux/man-pages/man5/proc_pid_oom_score.5.html&lt;/a&gt;&amp;#160;&lt;a href="#fnref:13" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:14"&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html&lt;/a&gt;&amp;#160;&lt;a href="#fnref:14" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:14" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref2:14" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:15"&gt;
&lt;p&gt;&lt;a href="https://wiki.goframe.org/pages/viewpage.action?pageId=157646868" target="_blank" rel="noreferrer"&gt;https://wiki.goframe.org/pages/viewpage.action?pageId=157646868&lt;/a&gt;&amp;#160;&lt;a href="#fnref:15" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:16"&gt;
&lt;p&gt;&lt;a href="https://www.man7.org/conf/lca2019/cgroups_v2-LCA2019-Kerrisk.pdf" target="_blank" rel="noreferrer"&gt;https://www.man7.org/conf/lca2019/cgroups_v2-LCA2019-Kerrisk.pdf&lt;/a&gt;&amp;#160;&lt;a href="#fnref:16" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:17"&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html&lt;/a&gt;&amp;#160;&lt;a href="#fnref:17" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:18"&gt;
&lt;p&gt;&lt;a href="https://support.huaweicloud.com/usermanual-hce/hce_02_0072.html" target="_blank" rel="noreferrer"&gt;https://support.huaweicloud.com/usermanual-hce/hce_02_0072.html&lt;/a&gt;&amp;#160;&lt;a href="#fnref:18" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:19"&gt;
&lt;p&gt;&lt;a href="https://chrisdown.name/talks/cgroupv2/cgroupv2-fosdem.pdf" target="_blank" rel="noreferrer"&gt;https://chrisdown.name/talks/cgroupv2/cgroupv2-fosdem.pdf&lt;/a&gt;&amp;#160;&lt;a href="#fnref:19" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:20"&gt;
&lt;p&gt;&lt;a href="https://www.cnblogs.com/muahao/p/10109712.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/muahao/p/10109712.html&lt;/a&gt;&amp;#160;&lt;a href="#fnref:20" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title>PostgreSQL CLOG文件及其从库同步解析</title><link>https://lastdba.com/2024/09/03/postgresql-clog%E6%96%87%E4%BB%B6%E5%8F%8A%E5%85%B6%E4%BB%8E%E5%BA%93%E5%90%8C%E6%AD%A5%E8%A7%A3%E6%9E%90/</link><pubDate>Tue, 03 Sep 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/09/03/postgresql-clog%E6%96%87%E4%BB%B6%E5%8F%8A%E5%85%B6%E4%BB%8E%E5%BA%93%E5%90%8C%E6%AD%A5%E8%A7%A3%E6%9E%90/</guid><description>&lt;p&gt;放眼所有关系型数据库，PostgreSQL的clog也是很特殊的日志。CLOG的存在跟PG的MVCC机制不无关系。一些事务ID、clog的基础知识本篇不会涉及，感谢兴趣的可参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782857?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172343394916800211586382%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172343394916800211586382&amp;amp;biz_id=0&amp;amp;utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-130782857-null-null.nonecase&amp;amp;utm_term=clog&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;clog和hintbits&lt;/a&gt;。本篇主要讲clog文件的构成、手工定位事务状态、clog的wal日志同步机制，以进一步理解PostgreSQL的clog。&lt;/p&gt;</description><content:encoded>&lt;p&gt;放眼所有关系型数据库，PostgreSQL的clog也是很特殊的日志。CLOG的存在跟PG的MVCC机制不无关系。一些事务ID、clog的基础知识本篇不会涉及，感谢兴趣的可参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782857?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172343394916800211586382%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172343394916800211586382&amp;amp;biz_id=0&amp;amp;utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-130782857-null-null.nonecase&amp;amp;utm_term=clog&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;clog和hintbits&lt;/a&gt;。本篇主要讲clog文件的构成、手工定位事务状态、clog的wal日志同步机制，以进一步理解PostgreSQL的clog。&lt;/p&gt;

&lt;h2 class="relative group"&gt;clog segment
 &lt;div id="clog-segment" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog-segment" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;clog目录
 &lt;div id="clog目录" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog%e7%9b%ae%e5%bd%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;为了区别普通日志，PG 10对clog和wal的目录进行了重命名&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;pg9.6&lt;/th&gt;
 &lt;th&gt;pg10&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_clog&lt;/td&gt;
 &lt;td&gt;pg_xact&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_xlog&lt;/td&gt;
 &lt;td&gt;pg_wal&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;别搞错了，我也有段时间被pg_xlog和pg_xact给困扰···&lt;/p&gt;

&lt;h3 class="relative group"&gt;clog segment name
 &lt;div id="clog-segment-name" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog-segment-name" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;clog也是由slru管理，clog文件命名也在&lt;code&gt;slru.c&lt;/code&gt;中&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define SlruFileName(ctl, path, seg) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	snprintf(path, MAXPGPATH, &amp;#34;%s/%04X&amp;#34;, (ctl)-&amp;gt;Dir, seg)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;%04X&lt;/code&gt;表示十六进制（&lt;code&gt;X&lt;/code&gt;），宽度为4、不足前面补0（&lt;code&gt;04&lt;/code&gt;）。
clog文件名示例如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg_xact&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; 16:29 03C0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 23:04 03C1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;TransactionID与clog位置的转换
 &lt;div id="transactionid与clog位置的转换" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#transactionid%e4%b8%8eclog%e4%bd%8d%e7%bd%ae%e7%9a%84%e8%bd%ac%e6%8d%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;clog只存储事务ID的状态，不存事务ID本身。通过TransactionID本身是可以直接定位到clog文件及文件中的位置的。在此之前我们需要了解一些基础知识。&lt;/p&gt;

&lt;h3 class="relative group"&gt;CLOG保存的事务状态
 &lt;div id="clog保存的事务状态" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog%e4%bf%9d%e5%ad%98%e7%9a%84%e4%ba%8b%e5%8a%a1%e7%8a%b6%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务的状态只有4种：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; XidStatus;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_IN_PROGRESS		0x00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_COMMITTED		0x01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_ABORTED		0x02
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_SUB_COMMITTED	0x03&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;事务状态只有进行中、已提交、回滚、子事务已提交。注意事务id没有“未开始”这个状态，只要数据库中分配了事务ID，那么这个事务肯定是已经开始了。
相反，库中还没有分配的事务ID（实际是少许，参考下面的extend clog章节），在clog中对应in_progress状态。
4个事务状态实际上2个bit位即可存储。那么1个字节（8 bits）可存储4个事务状态，1个页（8k）能放8KB*4=32768个事务状态。这些都在源码中定义了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; Defines &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; CLOG page sizes. A page is the same BLCKSZ as is used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; everywhere &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; in Postgres.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//clog页大小=BLCKSZ=8k（默认） 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_BITS_PER_XACT	2 								 &lt;/span&gt;&lt;span style="color:#75715e"&gt;//一个事务状态占2个bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACTS_PER_BYTE 4 								 &lt;/span&gt;&lt;span style="color:#75715e"&gt;//1个字节可存放4个事务状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE) &lt;/span&gt;&lt;span style="color:#75715e"&gt;//1个页可存放32768个事务状态，8KB*4=32768
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACT_BITMASK ((1 &amp;lt;&amp;lt; CLOG_BITS_PER_XACT) - 1) &lt;/span&gt;&lt;span style="color:#75715e"&gt;//事务状态的bitmask位=((1&amp;lt;&amp;lt;2)-1)=3，用二进制表达为11
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define SLRU_PAGES_PER_SEGMENT	32 &lt;/span&gt;&lt;span style="color:#75715e"&gt;//1个segment有32个pages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;汇总：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1个clog segment有32个page&lt;/li&gt;
&lt;li&gt;1个clog page有8k（一般）&lt;/li&gt;
&lt;li&gt;1个bytes有4个事务状态&lt;/li&gt;
&lt;li&gt;1个事务状态占2 bit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;clog segment/page/bytes的转换
 &lt;div id="clog-segmentpagebytes的转换" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog-segmentpagebytes%e7%9a%84%e8%bd%ac%e6%8d%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务id对应在哪个CLOG段不太好找，它藏在注释里：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; Note: because TransactionIds are &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; bits and wrap around at &lt;span style="color:#ae81ff"&gt;0xFFFFFFFF&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; CLOG page numbering also wraps around at &lt;span style="color:#ae81ff"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;CLOG_XACTS_PER_PAGE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; and CLOG segment numbering at
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;CLOG_XACTS_PER_PAGE&lt;span style="color:#f92672"&gt;/&lt;/span&gt;SLRU_PAGES_PER_SEGMENT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//segment number=xid/CLOG_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT=xid/32768/32 //事务id对应在哪个CLOG段，xid/32768/32,需要转成16进制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;事务id对应对应到page、byte等比较清晰&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToPage(xid)	((xid) / (TransactionId) CLOG_XACTS_PER_PAGE) &lt;/span&gt;&lt;span style="color:#75715e"&gt;//事务id对应在哪个CLOG page,xid/32768
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) &lt;/span&gt;&lt;span style="color:#75715e"&gt;//事务id对应在上面page中的偏移量,xid%32768
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToByte(xid)	(TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE) &lt;/span&gt;&lt;span style="color:#75715e"&gt;//事务id对应在page中的第几个字节,(xid%32768)/4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToBIndex(xid)	((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)		&lt;/span&gt;&lt;span style="color:#75715e"&gt;//事务id对应在上面字节中的哪个bit index（注意是bit index不是bit本身）,xid%4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一般来说（8k的BLCKSZ），1个CLOG段有32个页面；1个CLOG段有32*8k字节，&lt;strong&gt;即CLOG文件大小固定256K&lt;/strong&gt;；1个CLOG段可存放4*32*8k个事务状态。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg_xact&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll &lt;span style="color:#75715e"&gt;# 256k的clog segment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; 16:29 03C0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 23:04 03C1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;clog bit位的转换
 &lt;div id="clog-bit位的转换" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog-bit%e4%bd%8d%e7%9a%84%e8%bd%ac%e6%8d%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;设置clog bit和获取clog bit的函数（对应&lt;code&gt;TransactionIdSetStatusBit&lt;/code&gt;和&lt;code&gt;TransactionIdGetStatus&lt;/code&gt;）都有以下代码以获取事务id对应到clog中的哪两位bit：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			bshift &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdToBIndex&lt;/span&gt;(xid) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; CLOG_BITS_PER_XACT;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;byteptr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	byteptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; XactCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;shared&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;page_buffer[slotno] &lt;span style="color:#f92672"&gt;+&lt;/span&gt; byteno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	curval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;byteptr &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; bshift) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; CLOG_XACT_BITMASK;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;bshift&lt;/code&gt;表示右移的位置，其中&lt;code&gt;TransactionIdToBIndex=xid%4&lt;/code&gt;，&lt;code&gt;CLOG_BITS_PER_XACT=2&lt;/code&gt;，&lt;code&gt;CLOG_XACT_BITMASK=3（二进制为11）&lt;/code&gt;。
clog bit获取的关键代码&lt;code&gt;curval = (*byteptr &amp;gt;&amp;gt; bshift) &amp;amp; CLOG_XACT_BITMASK&lt;/code&gt;分两段来看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*byteptr &amp;gt;&amp;gt; bshift&lt;/code&gt;表示指针右移0、2、4、6位&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp; CLOG_XACT_BITMASK&lt;/code&gt;其实就是右移后取后两位（00&amp;amp;11=00、01&amp;amp;11=01、10&amp;amp;11=10、11&amp;amp;11=11）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;so，计算在一个byte中事务id状态的位置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;xid%4=0时，取第7、8位&lt;/li&gt;
&lt;li&gt;xid%4=1时，取第5、6位&lt;/li&gt;
&lt;li&gt;xid%4=2时，取第3、4位&lt;/li&gt;
&lt;li&gt;xid%4=3时，取第1、2位&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意，事务id状态在byte中的bit位是反着取的，不是正着顺序取。byte、page位这些是顺序递增的取的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;手动计算事务id在clog文件中的位置
 &lt;div id="手动计算事务id在clog文件中的位置" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%89%8b%e5%8a%a8%e8%ae%a1%e7%ae%97%e4%ba%8b%e5%8a%a1id%e5%9c%a8clog%e6%96%87%e4%bb%b6%e4%b8%ad%e7%9a%84%e4%bd%8d%e7%bd%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果我们要手工通过&lt;code&gt;hexdump&lt;/code&gt;定位CLOG中的事务，需要计算出三个元素&amp;lt;&lt;strong&gt;CLOG的段号、段中的偏移量in bytes、byte上的偏移量in bitindex&lt;/strong&gt;&amp;gt;。（这里参考了《PostgreSQL数据库内核分析》的说法，不过有一些区别&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;）&lt;/p&gt;
&lt;p&gt;计算之前还需要了解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;clog段文件号是16进制的&lt;/li&gt;
&lt;li&gt;hexdump是16进制的，每行存放16个字节，即每行存放&lt;code&gt;16*CLOG_XACTS_PER_BYTE=16*4=64&lt;/code&gt;个事务状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hexdump -s xxx&lt;/code&gt;是以byte为单位&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面sql可以计算transactionid对应clog中的位置：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--CLOG的段号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--%4294967296代表事务id回卷，/(8192*4*32)代表一个段文件能包含的最大事务数，to_hex转为文件名的16进制，lpad左补全4位
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lpad(&lt;span style="color:#66d9ef"&gt;upper&lt;/span&gt;(to_hex(txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;))),&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; clog_segmentno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--段中的偏移量in bytes 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--%4294967296代表事务id回卷，%(8192*32*4)取余下的事务id，/4计算成byte单位
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_clog_offset_bytes;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--byte上的偏移量in bitindex
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--%4294967296代表事务id回卷，%4取byte中的bitindex
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_byte_offset_bitindex;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--或者一条sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lpad(&lt;span style="color:#66d9ef"&gt;upper&lt;/span&gt;(to_hex(txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;))),&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; clog_segmentno,txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_clog_offset_bytes,txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_byte_offset_bitindex;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;实操模拟计算一个事务id在clog中的状态&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lpad(&lt;span style="color:#66d9ef"&gt;upper&lt;/span&gt;(to_hex(txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;))),&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; clog_segmentno,txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_clog_offset_bytes,txid_current()&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4294967296&lt;/span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; in_byte_offset_bitindex;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clog_segmentno &lt;span style="color:#f92672"&gt;|&lt;/span&gt; in_clog_offset_bytes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; in_byte_offset_bitindex 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------+----------------------+-------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0002&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;63196&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;checkpoint&lt;/span&gt;; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;rollback把事务回滚，主要是方便观察，因为大部分事务都是提交的。
checkpoint是未来保证clog page刷脏，不然clog page在clog buffer中还没写到clog segment文件。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd pg_xact&lt;span style="color:#f92672"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hexdump &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0002&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;s &lt;span style="color:#ae81ff"&gt;63196&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;n &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt;f6dc &lt;span style="color:#ae81ff"&gt;95&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;.&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt;f6dd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--十六进制转二进制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;x96&amp;#39;&lt;/span&gt;::bit(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bit 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;10010110&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;xid%4=3时，取第1、2位，所以这个回滚的事务的bit位取10，10代表&lt;code&gt;TRANSACTION_STATUS_ABORTED&lt;/code&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么clog中一般有很多55和U？
 &lt;div id="为什么clog中一般有很多55和u" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88clog%e4%b8%ad%e4%b8%80%e8%88%ac%e6%9c%89%e5%be%88%e5%a4%9a55%e5%92%8cu" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一般的业务事务库clog文件，直接hexdump的话结果就像下面这样：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hexdump &lt;span style="color:#f92672"&gt;-&lt;/span&gt;C &lt;span style="color:#ae81ff"&gt;0001&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;v&lt;span style="color:#f92672"&gt;|&lt;/span&gt;head &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000020&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000030&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000040&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000050&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000060&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;00000070&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;000000&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;000000&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;UUUUUUUUUUUUUUUU&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为事务提交的状态=01=&lt;code&gt;TRANSACTION_STATUS_COMMITTED&lt;/code&gt;，一个byte中4个连续的事务都是提交的，那么就是01010101。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二进制为01010101，十六进制为55&lt;/li&gt;
&lt;li&gt;十六进制55在ASCII中为U，所以在肉眼看CLOG文件一般可以看到很多U&lt;/li&gt;
&lt;li&gt;偶尔有些数组不是55或U，因为生产环境中偶尔有些事务没有完成或者使用了子事务。子事务在clog中的提交状态是x03。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;shared clog buffer
 &lt;div id="shared-clog--buffer" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shared-clog--buffer" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;clog shared buffers的个数很容易理解：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Number of shared CLOG buffers.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * On larger multi-processor systems, it is possible to have many CLOG page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * requests in flight at one time which could lead to disk access for CLOG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * page if the required page is not found in memory. Testing revealed that we
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * can get the best performance by having 128 CLOG buffers, more than that it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * doesn&amp;#39;t improve performance.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * a good idea, because it would increase the minimum amount of shared memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * required to start, which could be a problem for people running very small
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * configurations. The following formula seems to represent a reasonable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * compromise: people with very low values for shared_buffers will get fewer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * CLOG buffers as well, and everyone else will get 128.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;CLOGShmemBuffers&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Min&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Max&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, NBuffers &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;512&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;翻译：经过测试128个clog buffers性能是最好的，再多也提升不了性能。但是由于有些库的配置实在是太小了，128个clog buffers显得有点大，所以取shared buffers个数的1/512。也就是说：
clog buffers的个数=1/512 shared buffer，最小是4，最大是128。注意这里都是buffer的个数，不是大小！
那么单个buffer有多大呢？
clog buffer是slru管理的，slru每个page都是8k：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A page is the same BLCKSZ as is used everywhere&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;我们可以从clog slru初始化的角度窥探shared clog buffer的大小：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Initialization of shared memory for CLOG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;CLOGShmemSize&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleLruShmemSize&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;CLOGShmemBuffers&lt;/span&gt;(), CLOG_LSNS_PER_PAGE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;传入的&lt;code&gt;CLOGShmemBuffers()&lt;/code&gt;是4~128，传入的&lt;code&gt;CLOG_LSNS_PER_PAGE&lt;/code&gt;=1024 byte（8k page时）。
&lt;code&gt;SimpleLruShmemSize&lt;/code&gt;初始化slru shmem：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SimpleLruShmemSize&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; nslots, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; nlsns)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Size		sz;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* we assume nslots isn&amp;#39;t so large as to risk overflow */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(SlruSharedData));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;));	&lt;span style="color:#75715e"&gt;/* page_buffer[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(SlruPageStatus));	&lt;span style="color:#75715e"&gt;/* page_status[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;));	&lt;span style="color:#75715e"&gt;/* page_dirty[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;));	&lt;span style="color:#75715e"&gt;/* page_number[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;));	&lt;span style="color:#75715e"&gt;/* page_lru_count[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(LWLockPadded));	&lt;span style="color:#75715e"&gt;/* buffer_locks[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (nlsns &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		sz &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MAXALIGN&lt;/span&gt;(nslots &lt;span style="color:#f92672"&gt;*&lt;/span&gt; nlsns &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(XLogRecPtr));	&lt;span style="color:#75715e"&gt;/* group_lsn[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BUFFERALIGN&lt;/span&gt;(sz) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; BLCKSZ &lt;span style="color:#f92672"&gt;*&lt;/span&gt; nslots;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;slrus用一些数组保存slru的元数据和控制信息，sz大小都是&lt;code&gt;数据类型*buffer个数&lt;/code&gt;，这些大致估算都不是特别不大。主要初始化的内存还是&lt;code&gt;BLCKSZ * nslots&lt;/code&gt;，也就是&lt;code&gt;8k * (4~128)=(32k~1M)&lt;/code&gt;大小。所以可以&lt;em&gt;粗略的&lt;/em&gt;认为，shared clog buffer的大小为1M左右。&lt;/p&gt;

&lt;h2 class="relative group"&gt;CLOG的wal：类型、写入和redo
 &lt;div id="clog的wal类型写入和redo" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog%e7%9a%84wal%e7%b1%bb%e5%9e%8b%e5%86%99%e5%85%a5%e5%92%8credo" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;写clog的时候会写clog的wal日志吗？如果写了那不是clog丢了也可以通过wal日志再次应用就应该找回了事务状态？我们带着问题来看clog写wal和redo的源码。&lt;/p&gt;

&lt;h3 class="relative group"&gt;extend clog
 &lt;div id="extend-clog" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#extend-clog" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ZeroCLOGPage&lt;/code&gt;会写wal，&lt;code&gt;ZeroCLOGPage(pageno, true)&lt;/code&gt;实际上&lt;em&gt;仅&lt;/em&gt;由&lt;code&gt;ExtendCLOG&lt;/code&gt;调用：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Make sure that CLOG has room for a newly-allocated XID.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * NB: this is called while holding XidGenLock. We want it to be very fast
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * most of the time; even when it&amp;#39;s not so fast, no actual I/O need happen
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * unless we&amp;#39;re forced to write out a dirty clog or xlog page to make room
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * in shared memory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ExtendCLOG&lt;/span&gt;(TransactionId newestXact)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			pageno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * No work except at first XID of a page. But beware: just after
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * wraparound, the first XID of page zero is FirstNormalTransactionId.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdToPgIndex&lt;/span&gt;(newestXact) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdEquals&lt;/span&gt;(newestXact, FirstNormalTransactionId))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	pageno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdToPage&lt;/span&gt;(newestXact); &lt;span style="color:#75715e"&gt;//由TransactionId换算的clog page号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;LWLockAcquire&lt;/span&gt;(XactSLRULock, LW_EXCLUSIVE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Zero the page and make an XLOG entry about it */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;ZeroCLOGPage&lt;/span&gt;(pageno, true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;LWLockRelease&lt;/span&gt;(XactSLRULock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ZeroCLOGPage&lt;/code&gt;主要调用&lt;code&gt;WriteZeroPageXlogRec&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Write a ZEROPAGE xlog record
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;WriteZeroPageXlogRec&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; pageno)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;XLogBeginInsert&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;XLogRegisterData&lt;/span&gt;((&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) (&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pageno), &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;XLogInsert&lt;/span&gt;(RM_CLOG_ID, CLOG_ZEROPAGE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;WriteZeroPageXlogRec&lt;/code&gt;就是在写wal record了，写入的类型是“RM_CLOG_ID, CLOG_ZEROPAGE”。
通过waldump可以查看到CLOG_ZEROPAGE，它的占比一般都是非常少的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_waldump &lt;span style="color:#f92672"&gt;-&lt;/span&gt;z &lt;span style="color:#ae81ff"&gt;000000010000056&lt;/span&gt;B00000018 &lt;span style="color:#75715e"&gt;--stat=record
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; N (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;) Record &lt;span style="color:#66d9ef"&gt;size&lt;/span&gt; (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;) FPI &lt;span style="color:#66d9ef"&gt;size&lt;/span&gt; (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;) Combined &lt;span style="color:#66d9ef"&gt;size&lt;/span&gt; (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---- - --- ----------- --- -------- --- ------------- ---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLOG&lt;span style="color:#f92672"&gt;/&lt;/span&gt;ZEROPAGE &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ( &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;) &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; ( &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;) &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ( &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;) &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; ( &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;extend clog page时都是以page为单位，实际上在clog segment的末尾可以很容易看到00&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hexdump 03C2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000 5555 5555 5555 5555 5555 5555 5555 5555
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;001bb30 5555 5555 0055 0000 0000 0000 0000 0000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;001bb40 0000 0000 0000 0000 0000 0000 0000 0000 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;* ##clog文件后面的都是0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;001c000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;truncate clog
 &lt;div id="truncate-clog" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#truncate-clog" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;除了extend clog外，还有truncate clog，truncate clog会在vacuum期间被调用，调用时会写truncate clog的wal record，并将wal record flush到磁盘&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Remove all CLOG segments before the one holding the passed transaction ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Before removing any CLOG data, we must flush XLOG to disk, to ensure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * that any recently-emitted FREEZE_PAGE records have reached disk; otherwise
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * a crash and restart might leave us with some unfrozen tuples referencing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * removed CLOG data. We choose to emit a special TRUNCATE XLOG record too.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Replaying the deletion from XLOG is not critical, since the files could
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * just as well be removed later, but doing so prevents a long-running hot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * standby server from acquiring an unreasonably bloated CLOG directory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Since CLOG segments hold a large number of transactions, the opportunity to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * actually remove a segment is fairly rare, and so it seems best not to do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * the XLOG flush unless we have confirmed that there is a removable segment.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;TruncateCLOG&lt;/span&gt;(TransactionId oldestXact, Oid oldestxid_datoid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			cutoffPage;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * The cutoff point is the start of the segment containing oldestXact. We
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * pass the *page* containing oldestXact to SimpleLruTruncate.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//写入wal的是clog的位置，clog位置是oldestXact转换出来的clog page号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cutoffPage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdToPage&lt;/span&gt;(oldestXact); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.....
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Write XLOG record and flush XLOG to disk. We record the oldest xid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * we&amp;#39;re keeping information about here so we can ensure that it&amp;#39;s always
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * ahead of clog truncation in case we crash, and so a standby finds out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * the new valid xid before the next checkpoint.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// WriteTruncateXlogRec会写对应的wal record并将其写到磁盘上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;WriteTruncateXlogRec&lt;/span&gt;(cutoffPage, oldestXact, oldestxid_datoid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//wal写完后，才真正执行truncate clog段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Now we can remove the old CLOG segment(s) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;SimpleLruTruncate&lt;/span&gt;(XactCtl, cutoffPage);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;WriteTruncateXlogRec&lt;/code&gt;就是写&lt;code&gt;RMGR&lt;/code&gt;为&lt;code&gt;RM_CLOG_ID&lt;/code&gt;，&lt;code&gt;info&lt;/code&gt;为 &lt;code&gt;CLOG_TRUNCAT&lt;/code&gt;的wal record：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Write a TRUNCATE xlog record
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * We must flush the xlog record to disk before returning --- see notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * in TruncateCLOG().
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;WriteTruncateXlogRec&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; pageno, TransactionId oldestXact, Oid oldestXactDb)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	XLogRecPtr	recptr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	xl_clog_truncate xlrec;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	xlrec.pageno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pageno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	xlrec.oldestXact &lt;span style="color:#f92672"&gt;=&lt;/span&gt; oldestXact;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	xlrec.oldestXactDb &lt;span style="color:#f92672"&gt;=&lt;/span&gt; oldestXactDb;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;XLogBeginInsert&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;XLogRegisterData&lt;/span&gt;((&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) (&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;xlrec), &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(xl_clog_truncate));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	recptr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;XLogInsert&lt;/span&gt;(RM_CLOG_ID, CLOG_TRUNCATE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;XLogFlush&lt;/span&gt;(recptr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当制造了clog wal record后，还需要redo恢复的routine：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * CLOG resource manager&amp;#39;s routines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;clog_redo&lt;/span&gt;(XLogReaderState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;record)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//redo info类型是CLOG_ZEROPAGE时，将读取出来的redo信息放在内存，然后写到CLOG page文件中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (info &lt;span style="color:#f92672"&gt;==&lt;/span&gt; CLOG_ZEROPAGE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			pageno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			slotno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pageno, &lt;span style="color:#a6e22e"&gt;XLogRecGetData&lt;/span&gt;(record), &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;LWLockAcquire&lt;/span&gt;(XactSLRULock, LW_EXCLUSIVE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		slotno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZeroCLOGPage&lt;/span&gt;(pageno, false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SimpleLruWritePage&lt;/span&gt;(XactCtl, slotno); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;XactCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;shared&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;page_dirty[slotno]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;LWLockRelease&lt;/span&gt;(XactSLRULock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//redo info类型是CLOG_TRUNCATE时，将读取出来的redo信息放在内存中，确认page是可删除的（如果不可用需要write page），然后truncate segment
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (info &lt;span style="color:#f92672"&gt;==&lt;/span&gt; CLOG_TRUNCATE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		xl_clog_truncate xlrec;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;xlrec, &lt;span style="color:#a6e22e"&gt;XLogRecGetData&lt;/span&gt;(record), &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(xl_clog_truncate));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * During XLOG replay, latest_page_number isn&amp;#39;t set up yet; insert a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * suitable value to bypass the sanity test in SimpleLruTruncate.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		XactCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;shared&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;latest_page_number &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xlrec.pageno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;AdvanceOldestClogXid&lt;/span&gt;(xlrec.oldestXact);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SimpleLruTruncate&lt;/span&gt;(XactCtl, xlrec.pageno);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;elog&lt;/span&gt;(PANIC, &lt;span style="color:#e6db74"&gt;&amp;#34;clog_redo: unknown op code %u&amp;#34;&lt;/span&gt;, info);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;clog redo routine所做的事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;redo info类型是&lt;code&gt;CLOG_ZEROPAGE&lt;/code&gt;时，找到一个合适的slot（如果没有需要换出），根据读取出来的redo信息（实际上是clog page号）进行一些是否可写的判断，可以再讲page write到clog文件&lt;/li&gt;
&lt;li&gt;redo info类型是&lt;code&gt;CLOG_TRUNCATE&lt;/code&gt;时，根据读取出来的redo信息（实际上是clog page号），确认page是可删除的（如果不可用需要write page），然后truncate clog segment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;clog的同步小结
 &lt;div id="clog的同步小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#clog%e7%9a%84%e5%90%8c%e6%ad%a5%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;CLOG只有两种wal日志，两种都不包含事务状态信息，且仅仅是在extend clog page和truncate clog segment时触发，写入的wal record只是一个clog page编号。
CLOG的wal日志RMGR类型只有一种&lt;code&gt;RM_CLOG_ID&lt;/code&gt;，这种类型只有两种信息：&lt;code&gt;CLOG_ZEROPAGE&lt;/code&gt;、&lt;code&gt;CLOG_TRUNCATE&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* XLOG stuff */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_ZEROPAGE 0x00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_TRUNCATE 0x10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;clog wal同步总结：
&lt;strong&gt;从库本质上没有在同步clog信息，只是同步了一些clog文件的扩容和删除信息&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但是，从库的clog文件中明明是有状态信息的，从库明显也需要这部分信息以提供可见性检查。clog中的事务状态是怎么同步的呢？&lt;/p&gt;

&lt;h2 class="relative group"&gt;事务id的wal：类型、写入和redo
 &lt;div id="事务id的wal类型写入和redo" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e7%9a%84wal%e7%b1%bb%e5%9e%8b%e5%86%99%e5%85%a5%e5%92%8credo" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;rmgr=clog的wal不包含事务状态，难道从库不同步clog事务信息？并不是，wal日志中有事务ID的状态信息，clog也会被更新：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--回滚一个事务，提交一个事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; txid_current();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; txid_current 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1817254&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; txid_current();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; txid_current 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1817258&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;checkpoint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CHECKPOINT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--pg_waldump查看日志中的事务ID状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[datalzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_wal]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pg_waldump ..&lt;span style="color:#f92672"&gt;/&lt;/span&gt;..&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_wal&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;000000010000007300000008&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep &lt;span style="color:#f92672"&gt;-&lt;/span&gt;E &lt;span style="color:#e6db74"&gt;&amp;#34;1817254|1817258&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: &lt;span style="color:#66d9ef"&gt;Transaction&lt;/span&gt; len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;1817254&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;ED210, prev &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;ED1E0, &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ABORT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;41&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;017612&lt;/span&gt; CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: &lt;span style="color:#66d9ef"&gt;Transaction&lt;/span&gt; len (rec&lt;span style="color:#f92672"&gt;/&lt;/span&gt;tot): &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt;, tx: &lt;span style="color:#ae81ff"&gt;1817258&lt;/span&gt;, lsn: &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;EEB08, prev &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;EEAD8, &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;41&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;042545&lt;/span&gt; CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_waldump: fatal: error &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; WAL record &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;F7C78: invalid record &lt;span style="color:#66d9ef"&gt;length&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;F7F88: wanted &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, got &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在wal中有记录事务ID（1817254，1817258）的状态，并且分别记录为&lt;code&gt;ABORT&lt;/code&gt;、&lt;code&gt;COMMIT&lt;/code&gt; ；rmgr为&lt;code&gt;Transaction&lt;/code&gt;。
事务ID状态在wal日志中，但是pg会写到从库的clog里吗？
很明显，我们需要找到这部分的redo信息。按照刚才的经验，&lt;code&gt;clog_redo&lt;/code&gt;代表rmgr=clog的wal redo源码，那么源码搜索&lt;code&gt;_redo&lt;/code&gt;应该能找到rmgr=transactionid的wal redo源码。搜搜，在&lt;code&gt;xact.c&lt;/code&gt;中的找到函数&lt;code&gt;xact_redo&lt;/code&gt;，其主要调用&lt;code&gt;xact_redo_commit&lt;/code&gt;,&lt;code&gt;xact_redo_abort&lt;/code&gt;，明显各自对应提交事务和回退事务的wal日志应用逻辑。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;xact_redo&lt;/span&gt;(XLogReaderState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;record)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint8		info &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;XLogRecGetInfo&lt;/span&gt;(record) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; XLOG_XACT_OPMASK;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Backup blocks are not used in xact records */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;XLogRecHasAnyBlockRefs&lt;/span&gt;(record));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (info &lt;span style="color:#f92672"&gt;==&lt;/span&gt; XLOG_XACT_COMMIT)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;xact_redo_commit&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;parsed, &lt;span style="color:#a6e22e"&gt;XLogRecGetXid&lt;/span&gt;(record),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 record&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;EndRecPtr, &lt;span style="color:#a6e22e"&gt;XLogRecGetOrigin&lt;/span&gt;(record));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (info &lt;span style="color:#f92672"&gt;==&lt;/span&gt; XLOG_XACT_ABORT)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;xact_redo_abort&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;parsed, &lt;span style="color:#a6e22e"&gt;XLogRecGetXid&lt;/span&gt;(record));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;elog&lt;/span&gt;(PANIC, &lt;span style="color:#e6db74"&gt;&amp;#34;xact_redo: unknown op code %u&amp;#34;&lt;/span&gt;, info);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以commit为例&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;xact_redo_commit&lt;/span&gt;(xl_xact_parsed_commit &lt;span style="color:#f92672"&gt;*&lt;/span&gt;parsed,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 TransactionId xid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 XLogRecPtr lsn,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 RepOriginId origin_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (standbyState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; STANDBY_DISABLED)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * Mark the transaction committed in pg_xact.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;TransactionIdCommitTree&lt;/span&gt;(xid, parsed&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nsubxacts, parsed&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxacts);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&lt;span style="color:#75715e"&gt;//standby逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * Mark the transaction committed in pg_xact. We use async commit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * protocol during recovery to provide information on database
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * consistency for when users try to set hint bits. It is important
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * that we do not set hint bits until the minRecoveryPoint is past
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * this commit record. This ensures that if we crash we don&amp;#39;t see hint
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * bits set on changes made by transactions that haven&amp;#39;t yet
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * recovered. It&amp;#39;s unlikely but it&amp;#39;s good to be safe.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//在pg_xact中标记事务提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;TransactionIdAsyncCommitTree&lt;/span&gt;(xid, parsed&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nsubxacts, parsed&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxacts, lsn);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;看着&lt;code&gt;TransactionIdAsyncCommitTree&lt;/code&gt;就是我们要找的写clog的函数。&lt;/p&gt;
&lt;p&gt;为了验证wal中事务commit信息的redo逻辑，下面给从库的startup进程打三个断点，然后在源库执行&lt;code&gt;begin;select txid_current();commit;&lt;/code&gt;提交一个事务，看看从库的startup进程在做redo的时候是否命中我们想要看到的函数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(gdb) bt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#0 TransactionIdAsyncCommitTree (xid=xid@entry=1818665, nxids=0, xids=0x0, lsn=lsn@entry=495398394064) at transam.c:274
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#1 0x000000000050c139 in xact_redo_commit (parsed=parsed@entry=0x7ffda52c0fc0, xid=1818665, lsn=495398394064, origin_id=&amp;lt;optimized out&amp;gt;) at xact.c:5805
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#2 0x000000000050ffa3 in xact_redo (record=0x2b5ff2434038) at xact.c:5962
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#3 0x0000000000519ea5 in StartupXLOG () at xlog.c:7411
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#4 0x000000000072f301 in StartupProcessMain () at startup.c:204
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#5 0x0000000000528701 in AuxiliaryProcessMain (argc=argc@entry=2, argv=argv@entry=0x7ffda52c6ef0) at bootstrap.c:450
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#6 0x000000000072c459 in StartChildProcess (type=StartupProcess) at postmaster.c:5494
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#7 0x000000000072ec44 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x2b5ff242d1c0) at postmaster.c:1407
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#8 0x000000000048931f in main (argc=3, argv=0x2b5ff242d1c0) at main.c:210
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(gdb) info b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Num Type Disp Enb Address What
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; breakpoint keep y &lt;span style="color:#ae81ff"&gt;0x000000000050c060&lt;/span&gt; in xact_redo_commit at xact.c:&lt;span style="color:#ae81ff"&gt;5753&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; breakpoint already hit &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; times
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; breakpoint keep y &lt;span style="color:#ae81ff"&gt;0x0000000000508190&lt;/span&gt; in TransactionIdCommitTree at transam.c:&lt;span style="color:#ae81ff"&gt;262&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; breakpoint keep y &lt;span style="color:#ae81ff"&gt;0x00000000005081a0&lt;/span&gt; in TransactionIdAsyncCommitTree at transam.c:&lt;span style="color:#ae81ff"&gt;274&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; breakpoint already hit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; time&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以命中断点&lt;code&gt;TransactionIdAsyncCommitTree &lt;/code&gt;，并且&lt;code&gt;xid=1818665&lt;/code&gt;，也就是刚才在源库提交的事务ID。说明刚才肉眼看的代码逻辑没有问题。
so，&lt;strong&gt;standby库的clog事务ID状态由wal rmgr=Transaction来同步&lt;/strong&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;总结
 &lt;div id="总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;clog只存储了事务ID的状态，没有存储事务ID本身&lt;/li&gt;
&lt;li&gt;可以通过事务ID手动定位到CLOG文件中的事务状态&lt;/li&gt;
&lt;li&gt;rmgr=clog的wal只有扩展和清理clog文件，没有更新事务状态&lt;/li&gt;
&lt;li&gt;rmgr=transaction的wal会更新clog的事务状态&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;references
 &lt;div id="references" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;《快速掌握PostgreSQL版本新特性》p24&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;阎书利 PostgreSQL的CLOG解析 &lt;a href="https://www.modb.pro/db/606433" target="_blank" rel="noreferrer"&gt;https://www.modb.pro/db/606433&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;《PostgreSQL数据库内核分析》第7章 p380-390&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title>PostgreSQL流复制</title><link>https://lastdba.com/2024/08/13/postgresql%E6%B5%81%E5%A4%8D%E5%88%B6/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/postgresql%E6%B5%81%E5%A4%8D%E5%88%B6/</guid><description>&lt;h4 class="relative group"&gt;什么是PG流复制？
 &lt;div id="什么是pg流复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afpg%e6%b5%81%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Streaming Replication是pg9.0开始提供的传递WAL日志的方式，只要primary库一产生日志，就会立马传递到standby库。
在pg9.0之前，pg只能一个个传送wal日志(log shipping)，备库至少比主库落后一个wal日志



&lt;img src="https://lastdba.com/img/csdn/973437b5ba70.png" alt="PG流复制原理" /&gt;&lt;/p&gt;</description><content:encoded>
&lt;h4 class="relative group"&gt;什么是PG流复制？
 &lt;div id="什么是pg流复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afpg%e6%b5%81%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Streaming Replication是pg9.0开始提供的传递WAL日志的方式，只要primary库一产生日志，就会立马传递到standby库。
在pg9.0之前，pg只能一个个传送wal日志(log shipping)，备库至少比主库落后一个wal日志



&lt;img src="https://lastdba.com/img/csdn/973437b5ba70.png" alt="PG流复制原理" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;pg流复制进程
 &lt;div id="pg流复制进程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e6%b5%81%e5%a4%8d%e5%88%b6%e8%bf%9b%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;wal sender&lt;/strong&gt;：wal sender存在于主库。wal sender进程将主库最新LSN到备库最新的LSN之间的wal 传递给备库
&lt;strong&gt;wal receiver&lt;/strong&gt;：wal receiver存在于备库。wal receiver进程将备库最新的LSN号传递给主库。wal receiver接收wal sender传递过来的WAL数据并写入WAL日志
&lt;strong&gt;startup&lt;/strong&gt;：备库实例恢复进程。将wal日志在备库上重放&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;16776&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14632&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 13:33 ? 00:00:00 postgres: wal sender process lzl 172.17.100.150&lt;span style="color:#f92672"&gt;(&lt;/span&gt;13338&lt;span style="color:#f92672"&gt;)&lt;/span&gt; streaming 0/3002D30
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;16775&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15329&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 13:33 ? 00:00:00 postgres: wal receiver process streaming 0/3002D30
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;15330&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15329&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 10:26 ? 00:00:00 postgres: startup process recovering &lt;span style="color:#ae81ff"&gt;000000010000000000000003&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;pg流复制原理
 &lt;div id="pg流复制原理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e6%b5%81%e5%a4%8d%e5%88%b6%e5%8e%9f%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg流复制主要分为2个阶段，实例恢复阶段和主备同步阶段。
&lt;strong&gt;实例恢复阶段&lt;/strong&gt;：当pg库异常宕机后，数据库启动时，pg会重放宕机前的最后一个checkpoint之后的所有WAL日志（这跟oracle、mysql等关系型数据库实例恢复是同样的原理，目的就是把数据库置为一致性状态）。pg备库在搭建时，一般主库都是不停机的，此时备份主库出来的备份库处于不一致状态，在备库启动时statup进程将进行实例恢复操作
&lt;strong&gt;主备同步阶段&lt;/strong&gt;：wal receiver进程将备库最新的LSN号传递给主库，wal sender将主库最新LSN到备库最新的LSN之间的wal 传递给wal receiver，wal receiver接收WAL并将WAL写入到磁盘上，startup进程根据磁盘上的WAL日志在备库上重放&lt;/p&gt;

&lt;h4 class="relative group"&gt;同步和异步
 &lt;div id="同步和异步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%8c%e6%ad%a5%e5%92%8c%e5%bc%82%e6%ad%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg主从有5种模式，由synchronous_commit 参数控制。synchronous_commit 参数的本质就是控制主库什么时候提交。
&lt;strong&gt;remote_apply&lt;/strong&gt;：所有备库上均已应用完WAL时，主库提交。所以这个模式是同步模式，主从是一致的，主库上能查到的数据备库上一定也可以查到，这种模式下主备没有延时，但对主库提交时间有影响，因为主库commit需要等待网络传输和备库应用时间
ynchronous_commit的含义分2种情况，有从库和无从库时（synchronous_standby_name空或非空时）&lt;/p&gt;
&lt;p&gt;当synchronous_standby_name为非空时：
&lt;strong&gt;remote_apply&lt;/strong&gt;:从库已应用了wal，主库才可以提交。这种模式主从是同步的
&lt;strong&gt;on&lt;/strong&gt;：default。主从的wal都写到磁盘上时，主库提交。类似半同步，不会丢数据。
&lt;strong&gt;remote_write&lt;/strong&gt;：备库接收到wal并将wal日志写到文件系统cache上时，主库提交。此时从库的接收到wal但是还没有落盘，如果操作系统crash，会丢失数据。
&lt;strong&gt;local&lt;/strong&gt;：主库wal刷到磁盘时提交。这种模式是异步的，主库不需要确认备库状态就可以提交。
&lt;strong&gt;off&lt;/strong&gt;：本机wal没有刷到磁盘就可以提交，存在数据丢失风险，不推荐。&lt;/p&gt;
&lt;p&gt;当synchronous_standby_name为空时：
（当synchronous_standby_name为空时，synchronous_commit只有on和off有效，如果是remote_apply, remote_write and local ，那么仍然被认为是on）
&lt;strong&gt;on&lt;/strong&gt;：default。数据库wal写到磁盘上，事务才可以提交
&lt;strong&gt;off&lt;/strong&gt;：本机wal没有刷到磁盘就可以提交，存在数据丢失风险，不推荐。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主从同步关系&lt;/strong&gt;



&lt;img src="https://lastdba.com/img/csdn/43bd95ea31d5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主从可靠性&lt;/strong&gt;



&lt;img src="https://lastdba.com/img/csdn/647bc630a1ef.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;Failover
 &lt;div id="failover" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#failover" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;当主库crush时，备库就需要启动failover，此时备库就成为新主库。pg没有提供可以识别failure的方法，但是pg提供了激活主库的方法。（一般三方工具会调用pg激活方法，而主备监控、主库宕机判断、连接切换等等，都不是pg本身来做）
pg提供了2种方法将备库激活为主库：trigger_file文件和pg_ctl promote命令。(pg 12以后trigger_file变成promote_trigger_file）
trigger_file和pg_ctl promote在激活时都是一条命令就可以完成激活备库的任务，区别在于trigger_file需要在recover_file提前写好trigger_file配置
使用trigger_file做主备切换（pg_ctl promote同样的效果，比较简单）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;备库recovery.conf中配置trigger_file&lt;/li&gt;
&lt;li&gt;关闭主库&lt;/li&gt;
&lt;li&gt;touch trigger_file，将老备库启动为新主库&lt;/li&gt;
&lt;li&gt;配置recovery.conf，将老主库启动为新备库&lt;/li&gt;
&lt;li&gt;观察新老主备库&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;failover示例：&lt;/strong&gt;
环境：
主库	172.17.100.150	5432
备库	172.17.100.150	5433&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.备库recovery.conf中配置trigger_file&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat recovery.conf|grep trigger
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trigger_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/pg/pg96data_sla/trigger.kenyon&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ll /pg/pg96data_sla/trigger.kenyon
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls: cannot access /pg/pg96data_sla/trigger.kenyon: No such file or directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在recovery.conf中配置trigger文件路径就可以了，配置后不会出现trigger文件&lt;/p&gt;
&lt;p&gt;备库postgres.conf添加配置&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_wal_senders &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#75715e"&gt;#max_wal_senders是sender进程的最大数量，默认是0，所以切换前备库必须配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hot_standby&lt;span style="color:#f92672"&gt;=&lt;/span&gt;on &lt;span style="color:#75715e"&gt;#备库打开查询功能&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2.关闭主库&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pg_ctl stop -D /pg/pg96data_pri -m fast
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; server to shut down.... &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server stopped&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(判断主库WAL是否全部被备库应用：pg9.6- cd pg_xlog;pg 10+ cd pg_wal)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls -ltr|tail -n &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $NF}&amp;#39;&lt;/span&gt;|&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; read xlog;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; pg_xlogdump $xlog;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;观察备库wal中有关键词shutdown&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.touch激活备库(或者 pg_ctl promote -D /pg/pg96data_sla&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ touch /pg/pg96data_sla/trigger.kenyon&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时recovery.conf变成recovery.done&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.主库设置为备库&lt;/strong&gt;
配置新备库recovery.conf文件，可以直接cp老备库的过来，修改IP和目录&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vi $新备库/recover.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;standby_mode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; on
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;primary_conninfo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;host=172.17.100.150 port=5433 user=lzl password=lzl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recovery_target_timeline &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;latest&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;配置postgres.conf，将hot_standby = on写入conf，表示备库开启查询&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vi $新备库/postgres.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hot_standby &lt;span style="color:#f92672"&gt;=&lt;/span&gt; on&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;启动新备库&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/pg/pg96/bin/pg_ctl -D /pg/pg96data_pri -l /pg/pg96data_pri/server.log start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;5.检查主备库&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;# \x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Expanded display is on.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;# select * from pg_stat_replication ;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&lt;span style="color:#f92672"&gt;[&lt;/span&gt; RECORD &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;----+------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pid | &lt;span style="color:#ae81ff"&gt;24766&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;usesysid | &lt;span style="color:#ae81ff"&gt;16384&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;usename | lzl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;application_name | walreceiver
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_addr | 172.17.100.150
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_hostname | 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_port | &lt;span style="color:#ae81ff"&gt;47345&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_start | 2021-07-30 07:44:05.582546+00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_xmin | 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;state | streaming
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sent_location | 0/4033790
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;write_location | 0/4033790
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;flush_location | 0/4033790
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replay_location | 0/4033790
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sync_priority | &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sync_state | async&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;pg_basebackup
 &lt;div id="pg_basebackup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_basebackup" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg_basebackup是pg自带的备份工具，它用来做pg的基础备份。pg_basebackup可以用作PITR，也可以用来构造log-shipping standby和stream standby。它是pg的物理备份工具。
&lt;a href="https://liuzhilong.blog.csdn.net/article/details/119533506" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net/article/details/119533506&lt;/a&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;pg_rewind
 &lt;div id="pg_rewind" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_rewind" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg_rewind可以用作pg主从的维护工具。当2个pg实例时间线（timeline）出现分叉时，pg_rewind可以做实例间的同步。（比如主库运行的情况下，备库failover后运行了一段时间，此时主备的时间线就出现了分叉）
&lt;a href="https://liuzhilong.blog.csdn.net/article/details/119250794" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net/article/details/119250794&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Replication Slots
 &lt;div id="replication-slots" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#replication-slots" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是pg复制槽？&lt;/strong&gt;
主从架构下，如果从库还没有收到wal日志，主库就把wal删除了，这样的lag就不能自动恢复。复制槽就是为了确保主库不会把那些还没有被传到从库的WAL日志给删除。
在没有使用复制槽的情况下，可能需要用 wal_keep_size/wal_keep_segment和 archive_command去确保wal日志不被删除，但这种方式总会保留过多的wal，且在延时较大时也不能保证wal一定不会被删除。所以复制槽就是为此而生。
但是复制槽可能会导致主库一直不删除wal（比如从库已宕机的情况）导致磁盘被撑满，这时就需要max_slot_wal_keep_size来设置wal文件的保留上限。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;复制槽参数：&lt;/strong&gt;
&lt;strong&gt;max_slot_wal_keep_size&lt;/strong&gt;：在有复制槽时，该参数定义pg_wal目录下wal文件的最大大小。默认值为-1，表示主库为从库保留wal文件的大小没有上限。
&lt;strong&gt;wal_keep_segments&lt;/strong&gt;/&lt;strong&gt;wal_keep_size&lt;/strong&gt;:pg12及以下为wal_keep_segments，pg13及以上为wal_keep_size。保证pg_wal下的wal文件不会被删除。在没有复制槽的情况下，wal文件超过该大小就可能被删除，可能导致从库不可追日志。如果调整的过大，可能导致目录被撑的很大。该参数默认为0，也就是不保留WAL文件。如果wal被删除，可能会出现如下报错
&lt;code&gt;ERROR: requested WAL segment xxxx has already been removed&lt;/code&gt;
这时从库只能期待有归档，否则只要重搭。
&lt;strong&gt;primary_slot_name&lt;/strong&gt;：设置slot的名字，表示pg主从开启复制槽。所以开启pg复制槽至少有类似下面的配置
primary_conninfo = &amp;lsquo;host=172.17.100.150 port=5433 user=lzl password=lzl&amp;rsquo;
primary_slot_name = &amp;lsquo;pg_slot_lzl&amp;rsquo;
&lt;strong&gt;max_replication_slots&lt;/strong&gt;:复制槽的最大个数，重启生效。如果使用的复制槽不足，从库将启动失败。应将该值设置的较大。在pg9.6版本以下，默认值为0，pg10以上为10。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;创建pg复制槽&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.设置主库max_replication_slots参数&lt;/strong&gt;
主库：（我的pg版本为9.6)
max_replication_slots=10
加入postgres.conf，并重启主库&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.创建复制槽&lt;/strong&gt;
创建复制槽：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_create_physical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;pg_slot_lzl&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xlog_position 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_slot_lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看复制槽&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; slot_name, slot_type, active &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_replication_slots;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; slot_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----------+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_slot_lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; physical &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3.设置从库primary_slot_name参数&lt;/strong&gt;
&lt;code&gt;primary_slot_name = 'pg_slot_lzl'&lt;/code&gt;
加入recovery.conf,并重启从库&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.查看复制槽&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;,pg_xlogfile_name(restart_lsn)&lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; current_xxlog &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_replication_slots;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plugin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; slot_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active_pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; catalog_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; restart_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; confirmed_flush_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; current_xxlog 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------+--------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_slot_lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; physical &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12802&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A002340 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000002000000000000000&lt;/span&gt;A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--pg_xlogfile_name(restart_lsn)查看当前wal日志信息&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;查询冲突
 &lt;div id="查询冲突" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9f%a5%e8%af%a2%e5%86%b2%e7%aa%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;什么是查询冲突？&lt;/strong&gt;
备库在查询时可能会遇到如下错误
&lt;code&gt;ERROR：canceling statement due to confilct with recovery&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;为什么会产生冲突呢？我们细想一下，比如说备库正在执行基于某个表的查询（这个查询可能是应用产生的，也可能是手动连接进行的查询），这时主库执行了drop table操作，该操作写入wal日志后传至备库进行应用，为了保证数据一致性，postgresql必然会迅速回放数据，这时drop table和select就会形成冲突。如下图所示：



&lt;img src="https://lastdba.com/img/csdn/2d333af63baa.png" alt="ddl时查询冲突" /&gt;&lt;/p&gt;
&lt;p&gt;冲突场景：
上面只介绍了1种查询冲突的情况。总结一下有以下几种情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;主库排他锁（包括显示LOCK命令和各种DDL）&lt;/li&gt;
&lt;li&gt;主库vacuum清理死元组，从库如果正在使用该元组，就会产生冲突&lt;/li&gt;
&lt;li&gt;主库删除了从库查询正在使用的表空间&lt;/li&gt;
&lt;li&gt;主库删除了从库正在使用的数据库



&lt;img src="https://lastdba.com/img/csdn/2194edd3e8af.png" alt="vacuum时查询冲突" /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;试想在仅有主库的情况下：
场景1：一个会话发起了drop table，此时发现有select语句正在执行，那么该会话只能等待select完成其事务。
场景2：一个会话发起vacuum或后台自动vacuum，不会与当前库查询发生冲突，因为vacuum不会清理正在使用的元组。&lt;/p&gt;
&lt;p&gt;从库的处理就不同。因为主库不知道从库的事务状态，而从库又需要与主库保持一致，所以才发生了“查询冲突”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查询冲突参数&lt;/strong&gt;
&lt;strong&gt;hot_standby_feedback：&lt;/strong&gt;
这个参数是查询冲突这个话题中提到最多的参数，下面我们详细探讨一下。我们假设在没有备库的情况下，会话1查询某行数据，会话2删除该数据，然后commit，此时会话2执行一次vacuum，我们知道这次vacuum并不会删除该行数据，因为会话1的事务还需要使用该元组，所以不会清理该元组。那么如果是主从呢？主库在准备进行vacuum时怎么知道从库还在进行查询，这就是设置该参数的意义，设置hot_standby_feedback参数之后备库会定期向主库通知最小活跃事务id（xmin）值，这样使得主库vacuum进程不会清理大于xmin值的事务。
这个参数有利于减少冲突的发生，但并不能完全避免冲突，其实细想一下，这个参数只是减少了由于主库vacuum死亡元组造成的冲突，并不能解决排他锁造成的冲突。或者由于网络中断造成的冲突，假如主备之间的网络中断后，备库就无法向主库正常发送xmin值，如果时间够长，主库在这段时间内还是会清理无用元组，这样网络恢复后就可能发生上面的vacuum造成的冲突。
值得注意的是hot_standby_feedback参数并不会覆盖主库上old_snapshot_threshold参数限定的值，old_snapshot_threshold参数限制了死亡元组的无限膨胀，当事务信息超过old_snapshot_threshold的限制时，依然会进行清理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;max_standby_streaming_delay&lt;/strong&gt;：
备机因为接收wal流日志产生查询冲突而取消查询之前的等待时间，设置该参数会在发生冲突时，备库查询不会立即取消，而是等待一个时间后如果还没结束再抛出报错。这个值的大小可以参考备库可能产生的长事务运行时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;max_standby_archive_delay&lt;/strong&gt;：
备机因为处理归档的wal日志产生查询冲突而取消查询之前的等待时间，和上面的参数类似。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vacuum_defer_cleanup_age&lt;/strong&gt;：
指定vacuum延迟清理死亡元组的事务数，vacuum会延迟清除无效的记录，延迟的事务个数通过vacuum_defer_cleanup_age进行设置。即vacuum和vacuum full操作不会立即清理刚刚被删除元组&lt;/p&gt;
&lt;p&gt;可以根据pg_stat_database和pg_stat_database_conflicts视图查看冲突发生的情况&lt;/p&gt;

&lt;h4 class="relative group"&gt;其他相关参数
 &lt;div id="其他相关参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b6%e4%bb%96%e7%9b%b8%e5%85%b3%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;传输参数&lt;/strong&gt;
&lt;strong&gt;max_wal_senders&lt;/strong&gt;：使用wal sender获取wal的服务最大个数，也就是从库+baseback客户端的最大个数。pg9.6默认为0，pg10以后默认为10。
&lt;strong&gt;wal_send_timeout&lt;/strong&gt;:wal传输xx秒失败后中断复制。该参数在从库宕机或者网络长期中断时，wal不会再尝试传输。默认60。0表示永
不中断复制
&lt;strong&gt;track_commit_timestamp&lt;/strong&gt;：记录事务的时间。默认是off。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主库参数&lt;/strong&gt;
&lt;strong&gt;synchronous_standby_names&lt;/strong&gt;：
在主库上配置，备机的复制列表。有下面几种方式（s1，s2，s3代表备机的application_name，配置在recovery.conf中）
synchronous_standby_names=&amp;lsquo;s1&amp;rsquo; 代表s1备机返回就可以提交。
synchronous_standby_names=&amp;lsquo;FIRST 2 (s1,s2,s3)&amp;rsquo; 代表s1，s2，s3三个备机中前两个s1和s2返回主库就可以提交。
synchronous_standby_names=&amp;lsquo;ANY 2 (s1,s2,s3)&amp;rsquo; 代表s1，s2，s3三个备机中任意两个备机返回主库就可以提交。
synchronous_standby_names=&amp;rsquo;*&amp;rsquo; &lt;em&gt;代表匹配任意主机，也就是任意主机返回就可以提交。
&lt;strong&gt;wal_level&lt;/strong&gt;：
wal日志级别，这个参数决定了有多少信息写入wal日志，默认是replica，这种模式支持复制和wal归档，同时支持备库只读查询。
minimal：除了实例crash恢复需要的记录，其他不记录，比如CREATE TABLE AS，CREATE INDEX，CLUSTER，COPY可以跳过，该模式记录的日志信息不足以支持wal归档和流复制。
logic：在replica的基础上增加一些信息以支持逻辑解码，该模式会增大wal日志的数量，尤其是大量的update，delete操作的库。
在9.6之前还有archive和hot_standby模式，映射到现在的replica模式。
&lt;strong&gt;synchronous_commit&lt;/strong&gt;：
前面已讲过，5种模式，各有优劣。
&lt;strong&gt;archive_mode&lt;/strong&gt; ：archive_mode =on表示打开归档
&lt;strong&gt;archive_command&lt;/strong&gt;：归档命令，pg归档直接调用操作系统命令。可以是简单cp命令到备份端
&lt;strong&gt;listen_addresses&lt;/strong&gt;：监听地址。&amp;rsquo;&lt;/em&gt;&amp;lsquo;表示所有IP都监听，默认为local&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从库参数&lt;/strong&gt;
&lt;strong&gt;hot_standby&lt;/strong&gt;：on表示打开从库只读
&lt;strong&gt;primary_conninfo&lt;/strong&gt;：从库连接主库的连接串。如primary_conninfo = &amp;lsquo;host=172.17.100.150 port=5432 user=lzl password=lzl&amp;rsquo;
trigger_file/promote_trigger_file：激活备库的激活文件。pg 12以前叫trigger_file，pg12及以后为promote_trigger_file
trigger_file和pg_ctl promote在激活时都是一条命令就可以完成激活备库，前面已经具体演示过
&lt;strong&gt;wal_receiver_create_temp_slot&lt;/strong&gt;：当没有slot时，临时起一个slot（命为primary_slot_name）。默认是off的。&lt;/p&gt;

&lt;h4 class="relative group"&gt;参考文档：
 &lt;div id="参考文档" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%82%e8%80%83%e6%96%87%e6%a1%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;《PostgreSQL修炼之道》
&lt;a href="https://www.postgresql.org/docs/current/warm-standby.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/warm-standby.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/13/high-availability.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/high-availability.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/runtime-config-replication.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/runtime-config-replication.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/13/runtime-config-wal.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/runtime-config-wal.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/app-pgbasebackup.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/app-pgbasebackup.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/hot-standby.html#HOT-STANDBY-CONFLICT" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/hot-standby.html#HOT-STANDBY-CONFLICT&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cloud.tencent.com/developer/article/1555354" target="_blank" rel="noreferrer"&gt;https://cloud.tencent.com/developer/article/1555354&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/29737" target="_blank" rel="noreferrer"&gt;https://www.modb.pro/db/29737&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/Streaming_Replication" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Streaming_Replication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/blog/2018/09/07/setting-up-streaming-replication-postgresql/" target="_blank" rel="noreferrer"&gt;https://www.percona.com/blog/2018/09/07/setting-up-streaming-replication-postgresql/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cybertec-postgresql.com/en/the-synchronous_commit-parameter/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/the-synchronous_commit-parameter/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/m15217321304/article/details/88850146" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/m15217321304/article/details/88850146&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.51cto.com/lishiyan/2460518?source=dra" target="_blank" rel="noreferrer"&gt;https://blog.51cto.com/lishiyan/2460518?source=dra&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL逻辑复制</title><link>https://lastdba.com/2024/08/13/postgresql%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/postgresql%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6/</guid><description>&lt;h3 class="relative group"&gt;什么是逻辑复制
 &lt;div id="什么是逻辑复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg逻辑复制基于逻辑解析（logicaldecoding），将wal日志流解析成一定格式输出（output），订阅节点收到解析后的数据进行应用。&lt;/p&gt;</description><content:encoded>
&lt;h3 class="relative group"&gt;什么是逻辑复制
 &lt;div id="什么是逻辑复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg逻辑复制基于逻辑解析（logicaldecoding），将wal日志流解析成一定格式输出（output），订阅节点收到解析后的数据进行应用。&lt;/p&gt;
&lt;p&gt;逻辑复制不同于流复制（物理复制）基于实例级别主从库物理结构上就是一样，逻辑复制可以基于表级别选择性复制。逻辑复制（Logical Replication）在官方文档里专指”复制-订阅“模式，其实有许多工具可以基于逻辑解析做异构数据库间数据同步。&lt;/p&gt;
&lt;p&gt;pg9.4 pglogical插件可以支持逻辑复制（&lt;a href="https://github.com/2ndQuadrant/pglogical" target="_blank" rel="noreferrer"&gt;https://github.com/2ndQuadrant/pglogical&lt;/a&gt;），pg10开始原生支持逻辑复制。&lt;/p&gt;
&lt;p&gt;逻辑复制可以用于数据库升级、异构数据迁移、表级数据同步链路、订阅数据流等等&lt;/p&gt;

&lt;h3 class="relative group"&gt;逻辑解析
 &lt;div id="逻辑解析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;逻辑解析可以将wal日志中的表数据变更解析成行数据流或sql文本，这些行数据流或sql文本可以被其他类型的数据库或软件消费。而具体的解析格式由outputplugin决定。&lt;/p&gt;

&lt;h3 class="relative group"&gt;复制槽
 &lt;div id="复制槽" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%8d%e5%88%b6%e6%a7%bd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在逻辑复制中，复制槽代表着数据变更流。跟物理复制槽一样，逻辑复制槽也可以保证复制异常中断后，相关的wal日志不被删除，以保证复制重连后仍然可以继续解析wal日志。一个数据库可以有多个复制槽，一个复制槽只有一个outputplugin，一个复制槽代表一条复制链路。复制槽本质上是用来管理复制链路的。不同于流复制可以没有复制槽，逻辑复制是必须有复制槽的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;output plugin
 &lt;div id="output-plugin" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#output-plugin" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;output plugin转换wal日志信息成复制槽所要的格式。pg中内置了一些outputplugin，也可以通过插件添加一些额外的outputplugin。每个逻辑复制槽都有一个output plugin用于解析wal相关工作。&lt;/p&gt;
&lt;p&gt;outputplugin使用回调函数管理解析。比如OUTPUT_PLUGIN_BINARY_OUTPUT ，OUTPUT_PLUGIN_TEXTUAL_OUTPUT 用于设置out_type是二进制还是文本。还有一些回调函数用于通知plugin事务数据变更，并把事务排序。回调函数当然不用我们人为使用，一些内置的outputplugin已经打包好了。&lt;/p&gt;
&lt;p&gt;每个output plugin都有一些不同的解析行为和输出格式&lt;/p&gt;

&lt;h4 class="relative group"&gt;几个常见的outputplugin
 &lt;div id="几个常见的outputplugin" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%87%a0%e4%b8%aa%e5%b8%b8%e8%a7%81%e7%9a%84outputplugin" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;test_decoding：这是一个outputplugin样例，相当于output plugin原始形态。官方文档说这是一个template，但是它仍然可以解析。这个output plugin是pg自带的，但需要在contrib中编译。&lt;/p&gt;
&lt;p&gt;pgoutput：发布订阅模式的默认outputplugin。在发布订阅中，walsender进程使用该outputplugin逻辑解码wal日志。&lt;/p&gt;
&lt;p&gt;decoder_raw:解析成sql文本格式。这个不是pg自带的，自行编译：&lt;a href="https://github.com/michaelpq/pg_plugins/tree/main/decoder_raw" target="_blank" rel="noreferrer"&gt;https://github.com/michaelpq/pg_plugins/tree/main/decoder_raw&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;wal2json：这个outputplugin会将wal日志信息转化为json格式&lt;/p&gt;
&lt;p&gt;有些其他的output plugin可参考：&lt;a href="https://wiki.postgresql.org/wiki/Logical_Decoding_Plugins" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Logical_Decoding_Plugins&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有些国内也有厂商做了自己outputplugin。&lt;/p&gt;
&lt;p&gt;几个output plugin和逻辑复制插件的关系：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8681978ee447.png" alt="5bc6c1dacf2c4f4888f2e299d3d75bc6.png" /&gt;


&lt;img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;pgoutput、test_decoding、wa2json上面已经介绍了&lt;/p&gt;
&lt;p&gt;pglogical在pg9.4是pglogical replication的前身&lt;/p&gt;
&lt;p&gt;BDR是2ndQuadrant开发，支持双向复制、DDL同步，功能更强大，BDR3.0开始闭源&lt;/p&gt;

&lt;h3 class="relative group"&gt;几个能手动接收解析数据的函数和工具
 &lt;div id="几个能手动接收解析数据的函数和工具" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%87%a0%e4%b8%aa%e8%83%bd%e6%89%8b%e5%8a%a8%e6%8e%a5%e6%94%b6%e8%a7%a3%e6%9e%90%e6%95%b0%e6%8d%ae%e7%9a%84%e5%87%bd%e6%95%b0%e5%92%8c%e5%b7%a5%e5%85%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg_logical_slot_get_changes()函数展示解析数据并消费掉;&lt;/p&gt;
&lt;p&gt;pg_logical_slot_peek_changes()函数展示解析数据不会消费掉；&lt;/p&gt;
&lt;p&gt;pg_recvlogical，pg自带的工具，能消费复制槽内的数据，相当于逻辑复制的下游。对应物理wal接收工具为 pg_receivewal&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;逻辑解析测试1&lt;/strong&gt;：观察用2个不同的output plugin解析数据
 &lt;div id="逻辑解析测试1观察用2个不同的output-plugin解析数据" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90%e6%b5%8b%e8%af%951%e8%a7%82%e5%af%9f%e7%94%a82%e4%b8%aa%e4%b8%8d%e5%90%8c%e7%9a%84output-plugin%e8%a7%a3%e6%9e%90%e6%95%b0%e6%8d%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建两个逻辑复制槽，分别使用logical_test和logical_raw
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_test&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;test_decoding&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_create_logical_replication_slot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (logical_test,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1756&lt;/span&gt;F50)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_raw&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;decoder_raw&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_create_logical_replication_slot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (logical_raw,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1756&lt;/span&gt;F88)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--只创建上游，slot是f状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_replication_slots; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plugin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; slot_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;temporary&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active_pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; catalog_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; restart_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; confirmed_flush_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wal_status &lt;span style="color:#f92672"&gt;|&lt;/span&gt; safe_wal_size 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+---------------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------+------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logical_test &lt;span style="color:#f92672"&gt;|&lt;/span&gt; test_decoding &lt;span style="color:#f92672"&gt;|&lt;/span&gt; logical &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16385&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;558&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1766878&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17668&lt;/span&gt;B0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reserved &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logical_raw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; decoder_raw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; logical &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16385&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;557&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1756&lt;/span&gt;F50 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1756&lt;/span&gt;F88 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reserved &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建一张表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tdecoder222(a int,b varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--尝试获得这个ddl
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_logical_slot_get_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_raw&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;include-xids&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#66d9ef"&gt;option&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;include-xids&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unknown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTEXT: slot &lt;span style="color:#e6db74"&gt;&amp;#34;logical_raw&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;output&lt;/span&gt; plugin &lt;span style="color:#e6db74"&gt;&amp;#34;decoder_raw&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; the startup callback
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_logical_slot_get_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_test&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;include-xids&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-----+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17669&lt;/span&gt;C8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;558&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776778&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;558&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--能看出decoder_raw完全没有解析ddl，logical_test只是获取了ddl的事物，没有ddl语句本身，相当于没解析ddl
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入一条数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_test&amp;#39;&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-----+---------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776890&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776890&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222: &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt;: a[integer]:&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776900&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_raw&amp;#39;&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-----+----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776890&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;560&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222 (a, b) &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--test_decoding解析了事物
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--decoder_raw把事务解析成了sql语句&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个测试可以得出结论：&lt;/p&gt;
&lt;p&gt;1.复制槽在f状态仍会解析，等待下游消费&lt;/p&gt;
&lt;p&gt;2.每个output plugin都有一些不同的解析行为和输出格式&lt;/p&gt;

&lt;h4 class="relative group"&gt;逻辑解析测试2：使用pg_recvlogical工具接收逻辑解析数据，模拟一个逻辑复制链路
 &lt;div id="逻辑解析测试2使用pg_recvlogical工具接收逻辑解析数据模拟一个逻辑复制链路" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90%e6%b5%8b%e8%af%952%e4%bd%bf%e7%94%a8pg_recvlogical%e5%b7%a5%e5%85%b7%e6%8e%a5%e6%94%b6%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90%e6%95%b0%e6%8d%ae%e6%a8%a1%e6%8b%9f%e4%b8%80%e4%b8%aa%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e9%93%be%e8%b7%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--配置免密登陆
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ vi .pgpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat .pgpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzl:5410:lzldb:pg:pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ chmod &lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; .pgpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--启动pg_recvlogical
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pg_recvlogical -h lzl -p &lt;span style="color:#ae81ff"&gt;5410&lt;/span&gt; -d lzldb -U pg --slot&lt;span style="color:#f92672"&gt;=&lt;/span&gt;logical_raw --start -f recv.sql &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ps -ef|grep recv|grep -v grep
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;7747&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7355&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 21:40 pts/3 00:00:00 pg_recvlogical -h lzl -p &lt;span style="color:#ae81ff"&gt;5410&lt;/span&gt; -d lzldb -U pg --slot&lt;span style="color:#f92672"&gt;=&lt;/span&gt;logical_raw --start -f recv.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;qwe&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;asd&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzl &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; tail &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;f recv.&lt;span style="color:#66d9ef"&gt;sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222 (a, b) &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;qwe&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--update没有正确解析
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--给表加主键
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;lzl2&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tdecoder222 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;lzlupdate&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzl &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; tail &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;f recv.&lt;span style="color:#66d9ef"&gt;sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222 (a, b) &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222 (a, b) &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;lzl2&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tdecoder222 &lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lzlupdate&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&amp;ndash;加了主键后update被decoder_raw正确解析&lt;/p&gt;
&lt;p&gt;&amp;ndash;没有主键不会正确解析，这跟replicaidentity复制标识相关，后面会介绍&lt;/p&gt;

&lt;h3 class="relative group"&gt;逻辑复制的前置条件
 &lt;div id="逻辑复制的前置条件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e7%9a%84%e5%89%8d%e7%bd%ae%e6%9d%a1%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;1.参数
 &lt;div id="1参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;1.1基本的必要参数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wal_level。重启生效，默认是replica。wal_level参数必须是logical。logical不是把wal改成逻辑的，它表示在支持物理复制（replica）的基础上增加逻辑解析所必要的信息。在pg9.6以后只有minimal、replica、logical，信息量依次递增。&lt;/li&gt;
&lt;li&gt;max_replication_slots。重启生效，在pg9.6版本以下默认值为0，pg10以上为10，10个一般都够了。与物理复制相同，逻辑复制一般也要用到复制槽。pg的备份、物理复制均可以占用到复制槽的数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1.2源端必要参数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;max_wal_senders。重启生效，默认10。sender进程数限制，发布端的sender传递解析后的日志。一般一个逻辑复制槽对应了一个sender和一个worker。这个跟物理复制类似，一个物理复制对应一个sender和一个receiver。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1.3目标端必要参数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;max_worker_processes。重启生效，默认8。工作进程数限制。并行进程（并行查询、并行统计信息收集等，这些并行进程由 max_parallel_workers限制）、逻辑复制工作进程（max_logical_replication_workers）和一些其他需要forkworker的程序均与该参数有关。应该设置为max_parallel_workers+逻辑复制应用端worker+其他后台worker。&lt;/li&gt;
&lt;li&gt;max_logical_replication_workers。重启生效，默认4。逻辑复制工作进程数，包括逻辑复制的应用工作进程和表同步工作进程。&lt;/li&gt;
&lt;li&gt;max_sync_workers_per_subscription。reload生效，默认2。逻辑同步新增表时同步工作进程，目前一张表只有一个并行。&lt;/li&gt;
&lt;li&gt;以上三个参数是梯度式的max_sync_workers_per_subscription&amp;lt;max_logical_replication_workers&amp;lt;max_worker_processes。总之得有worker可用。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;2 权限
 &lt;div id="2-权限" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-%e6%9d%83%e9%99%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;复制用户的权限。逻辑复制的用户需要有replication权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;ALTER ROLE &amp;lt;usename&amp;gt;WITH REPLICATION;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hba访问限制，允许下游使用复制用户访问数据库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;host lzldb user1 172.17.100.150/32 md5&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于发布订阅模式。需要database上的create权限或ssuperuser权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在创建发布时只有fortable至少需要带create权限的表owner，其余发布都必须要superuser&lt;/p&gt;
&lt;p&gt;在创建订阅时必须要superuser。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grant create on database lzl1db to owner1;&lt;/code&gt; 或者&lt;/p&gt;
&lt;p&gt;&lt;code&gt;alter user replicate1 superuser;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;另外复制过程中表的读或写权限也是必要的。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;pg间的逻辑同步——发布与订阅
 &lt;div id="pg间的逻辑同步发布与订阅" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e9%97%b4%e7%9a%84%e9%80%bb%e8%be%91%e5%90%8c%e6%ad%a5%e5%8f%91%e5%b8%83%e4%b8%8e%e8%ae%a2%e9%98%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg的内置逻辑复制基于发布订阅模型。发布与订阅模式不是解析成sql应用。&lt;/p&gt;

&lt;h4 class="relative group"&gt;发布
 &lt;div id="发布" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%91%e5%b8%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;发布者可以有多个发布，每个发布可以有多个表。&lt;/li&gt;
&lt;li&gt;发布时可以指定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;for table&lt;/code&gt; 发布某些表，新增表需要显示添加ALTER PUBLICATION ADD TABLE。创建此发布至少是表的owner。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for all tables&lt;/code&gt; 发布database下的所有表，新增表自动发布。创建此发布必须是superuser&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for all tables in schema&lt;/code&gt; 发布schema下的所有表，新增表自动发布。创建此发布必须是superuser。pg15开始支持&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发布默认包含INSERT, UPDATE, DELETE, and TRUNCATE，也可以指定复制某些命令。不同步DDL。（官方文档原话。也就是说truncate在pg里面不算ddl，这个留坑后面再研究。truncate在mysql和oracle中是ddl）&lt;/li&gt;
&lt;li&gt;只能发布基表；临时表、外部表、视图、序列等等都不能发布。分区表发布与pg版本和分区属性有关，pg15默认发布分区表所有分区&lt;/li&gt;
&lt;li&gt;publish_via_partition_root。pg13开始支持。该发布参数表示分区表使用分区进行过滤（fales，默认）还是用户父分区进行行过滤。如果设置为true，那么支持了异构分区表逻辑复制，比如分区表到普通表的复制。true时不能进行truncate复制。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;订阅
 &lt;div id="订阅" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%ae%a2%e9%98%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一个订阅只有一个发布者，但可订阅发布者上的多个发布。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;订阅者可以有多个订阅，每个订阅都会从一个复制槽中接收数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个订阅对应一个复制槽，这个复制槽在发布端。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在创建或删除订阅时，默认自动在发布者创建或删除复制槽。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建订阅必须要superuser&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DDL不会被同步，表必须是已建好的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存量数据默认同步，存量数据通过copy的方式快照拷贝到订阅者&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同步可以暂停和继续ALTER SUBSCRIPTION sub1 {ENABLE|DISABLE}&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当发布新增表后，需要在订阅端refresh。alter subscription sub1 refresh publication&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;发布和订阅的表schema名、表名、字段名必须一致，字段类型可以不一致（只要能隐式转换成功），字段顺序可以不一致。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;订阅还有些属性，比如二进制传输、流传输、同步提交、两阶段提交等&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/71469ba164fc.png" alt="d48af56aa7fc4df89b429605b2e049a9.png" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;logicalreplication launcher是用来启动订阅端的worker进程的，只在启动时存在&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*-------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * IDENTIFICATION
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * src/backend/replication/logical/launcher.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * NOTES
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * This module contains the logical replication worker launcher which
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * uses the background worker infrastructure to start the logical
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * replication workers for every enabled subscription.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *-------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;发布订阅相关视图
 &lt;div id="发布订阅相关视图" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%91%e5%b8%83%e8%ae%a2%e9%98%85%e7%9b%b8%e5%85%b3%e8%a7%86%e5%9b%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg_publication; &amp;ndash;查看发布。发布本身是无状态的，复制槽是有状态的，所以没有pg_stat_publication&lt;/p&gt;
&lt;p&gt;pg_publication_tables &amp;ndash;查看发布的表，简单明了&lt;/p&gt;
&lt;p&gt;pg_publication_rel &amp;ndash;查看发布的表，都是id&lt;/p&gt;
&lt;p&gt;pg_stat_subscription &amp;ndash;查看订阅状态，pid是worker进程的pid&lt;/p&gt;
&lt;p&gt;pg_subscription &amp;ndash;查看订阅&lt;/p&gt;
&lt;p&gt;pg_subscription_rel &amp;ndash;查看订阅表，没有pg_subscription_tables。另外该视图可以查看订阅下面各个表的同步情况，这是复制槽视图做不到的&lt;/p&gt;
&lt;p&gt;\dRp list replication publications&lt;/p&gt;
&lt;p&gt;\dRs list replication subscriptions&lt;/p&gt;

&lt;h2 class="relative group"&gt;创建一个发布和订阅
 &lt;div id="创建一个发布和订阅" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%ba%e4%b8%80%e4%b8%aa%e5%8f%91%e5%b8%83%e5%92%8c%e8%ae%a2%e9%98%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;用专门的复制用户replicate1，在库lzldb下创建一个发布和订阅，实现逻辑复制表trep1&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;code&gt;角色&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;主机ip&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;端口&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;库名&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;schema&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;表名&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;复制用户&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;版本&lt;/code&gt;&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;&lt;code&gt;172.17.100.150&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5410&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;lzldb&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;trep1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;replicate1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pg13&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;订阅节点&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;172.17.100.150&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5412&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;lzlbd&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;trep1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;replicate1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pg13&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 class="relative group"&gt;创建发布
 &lt;div id="创建发布" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%ba%e5%8f%91%e5%b8%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;修改&lt;/span&gt;postgres.conf&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;wal_level参数重启生效
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;logical 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;修改&lt;/span&gt;pg_hba.conf文件,reload生效
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;host&lt;/span&gt; lzldb replicate1 &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; md5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建复制用户并赋权
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; replicate1 &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; password &lt;span style="color:#e6db74"&gt;&amp;#39;replicate1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; replicate1 &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; replication;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; lzldb &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; replicate1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建要复制的表并授权给复制用户
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; lzldb replicate1 &lt;span style="color:#75715e"&gt;--如果复制用户不是表的owner，应该授权grantselect on trep1 to replicate1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; trep1(a int &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,b char(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; trep1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建发布，用superuser用户也可以
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; lzldb replicate1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; publication pub_lzl1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; trep1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看发布。\dRp或pg_publication
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_publication;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubowner &lt;span style="color:#f92672"&gt;|&lt;/span&gt; puballtables &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubinsert &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubupdate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubdelete &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubtruncate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pubviaroot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+----------+----------+--------------+-----------+-----------+-----------+-------------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16400&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pub_lzl1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16392&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;创建订阅
 &lt;div id="创建订阅" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%ba%e8%ae%a2%e9%98%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建表定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; trep1(a int &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,b char(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--用superuser用户创建订阅
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; SUBSCRIPTION sub_test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CONNECTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;host=172.17.100.150 port=5410 dbname=lzldb user=replicate1 password=replicate1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PUBLICATION pub_lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_subscription; &lt;span style="color:#75715e"&gt;--查看订阅。\dRs或pg_subscription
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subdbid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subowner &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subenabled &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subconninfo &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subslotname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subsynccommit &lt;span style="color:#f92672"&gt;|&lt;/span&gt; subpublications 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+---------+----------+----------+------------+--------------------------------------------------------------------------------+-------------+---------------+-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16394&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16384&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sub_test &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;host&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt; port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5410&lt;/span&gt; dbname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;lzldb &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;replicate1 password&lt;span style="color:#f92672"&gt;=&lt;/span&gt;replicate1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sub_test &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;pub_lzl1&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; trep1;&lt;span style="color:#75715e"&gt;--查看存量数据已同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;发布订阅模式 测试1:truncate同步
 &lt;div id="发布订阅模式-测试1truncate同步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%91%e5%b8%83%e8%ae%a2%e9%98%85%e6%a8%a1%e5%bc%8f-%e6%b5%8b%e8%af%951truncate%e5%90%8c%e6%ad%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; trep1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;TRUNCATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; trep1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---+---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; trep1; &lt;span style="color:#75715e"&gt;--发布订阅模式，truncate可以同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---+---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;发布订阅模式 测试2:新增表同步
 &lt;div id="发布订阅模式-测试2新增表同步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%91%e5%b8%83%e8%ae%a2%e9%98%85%e6%a8%a1%e5%bc%8f-%e6%b5%8b%e8%af%952%e6%96%b0%e5%a2%9e%e8%a1%a8%e5%90%8c%e6%ad%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--在已有发布订阅下，新增一个表同步。lzldb是发布者，lzlbd是订阅者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_pk(a int,b varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_pk &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; publication pub_lzl1 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_pk;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; PUBLICATION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--发布端新增表后需要在订阅端执行refresh，refresh默认同步存量数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; subscription sub_test refresh publication; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; SUBSCRIPTION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_subscription_rel ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; srsubid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srrelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srsubstate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srsublsn 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+---------+------------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16394&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16389&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;F2898
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16394&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16400&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; d &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--订阅的状态码： i = 初始化， d =正在复制数据， s = 已同步， r =准备好(普通复制)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时表tab_pk数据并没有同步，因为订阅端复制用户缺少查询表的权限
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; replicate1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_subscription_rel ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; srsubid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srrelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srsubstate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; srsublsn 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+---------+------------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16394&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16389&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;F2898
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16394&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16400&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;D830
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--订阅为ready状态，新增表同步完成&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;replica identity复制标识
 &lt;div id="replica-identity复制标识" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#replica-identity%e5%a4%8d%e5%88%b6%e6%a0%87%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;复制标识写进wal日志以标识一行数据。无论是发布订阅还是第三方逻辑同步工具，都需要定位表中的行，以标识update、delete到底作用在下游的哪一条数据。
pg中可以设置4种复制标识模式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;default(d) 非系统表的默认标识。表有主键就用主键，如果没有主键就是nothing&lt;/li&gt;
&lt;li&gt;index(i) 将一个非空唯一索引作为标识。必须是非空且唯一，这样才能标识一行。如果只是唯一，可以有多个空值。其实也可以显示指定主键为index模式。&lt;/li&gt;
&lt;li&gt;full(f) 将行的所有列作为标识。full模式会增大wal日志量&lt;/li&gt;
&lt;li&gt;nothing(n) 系统表的默认模式，没有标识，update、delete无法作用到下游&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;查看表的复制标识：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,relreplident &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;tabname1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当表的复制标识是&lt;/span&gt;i时&lt;span style="color:#960050;background-color:#1e0010"&gt;，查看索引是否是复制标识&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d tabname
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; rel.relname,idx.indisreplident &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index idx ,pg_class rel &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; idx.indexrelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rel.oid &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; relname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idx_1&amp;#39;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;修改表的复制标识：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; tab1REPLICA &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; index_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FULL&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOTHING&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;复制标识测试1：将一个没有主键的表的复制标识设置为非空唯一索引
 &lt;div id="复制标识测试1将一个没有主键的表的复制标识设置为非空唯一索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%8d%e5%88%b6%e6%a0%87%e8%af%86%e6%b5%8b%e8%af%951%e5%b0%86%e4%b8%80%e4%b8%aa%e6%b2%a1%e6%9c%89%e4%b8%bb%e9%94%ae%e7%9a%84%e8%a1%a8%e7%9a%84%e5%a4%8d%e5%88%b6%e6%a0%87%e8%af%86%e8%ae%be%e7%bd%ae%e4%b8%ba%e9%9d%9e%e7%a9%ba%e5%94%af%e4%b8%80%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_idx(a int,b varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,relreplident &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;tab_idx&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relreplident 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tab_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unique&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab_idx(b);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_idx &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--当做复制标识的索引必须是非空唯一索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; rel.relname,idx.indisreplident &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index idx ,pg_class rel &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; idx.indexrelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rel.oid &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; relname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idx_1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indisreplident 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_idx REPLICA &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_1; &lt;span style="color:#75715e"&gt;--修改表的复制标识
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; rel.relname,idx.indisreplident &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index idx ,pg_class rel &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; idx.indexrelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rel.oid &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; relname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idx_1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indisreplident 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d tab_idx &lt;span style="color:#75715e"&gt;--pg_index或者\d查看索引复制标识，\d只能查看显示修改的索引复制标识
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.tab_idx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------+-----------+----------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_1&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;UNIQUE&lt;/span&gt;, btree (b) REPLICA &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;复制标识测试2：full模式，多条重复数据时，是否可以正常同步
 &lt;div id="复制标识测试2full模式多条重复数据时是否可以正常同步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%8d%e5%88%b6%e6%a0%87%e8%af%86%e6%b5%8b%e8%af%952full%e6%a8%a1%e5%bc%8f%e5%a4%9a%e6%9d%a1%e9%87%8d%e5%a4%8d%e6%95%b0%e6%8d%ae%e6%97%b6%e6%98%af%e5%90%a6%e5%8f%af%e4%bb%a5%e6%ad%a3%e5%b8%b8%e5%90%8c%e6%ad%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--发布端执行一下命令
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_full (a int,b varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;--添加一个无主键和非空索引的表同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--插入相同的5条数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; replicate1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; publication tab_full &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_pk;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; PUBLICATION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; subscription sub_test refresh publication; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; SUBSCRIPTION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; ctid,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; ctid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;(0,2)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: cannot &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tab_full&amp;#34;&lt;/span&gt; because it does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; have a replica &lt;span style="color:#66d9ef"&gt;identity&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; publishes deletes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: &lt;span style="color:#66d9ef"&gt;To&lt;/span&gt; enable deleting &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; REPLICA &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; ctid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;(0,5)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: cannot &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tab_full&amp;#34;&lt;/span&gt; because it does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; have a replica &lt;span style="color:#66d9ef"&gt;identity&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; publishes updates
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: &lt;span style="color:#66d9ef"&gt;To&lt;/span&gt; enable updating the &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; REPLICA &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--当表的replica identity是d(default)时，没有主键就是nothing。nothing无法复制delete和update。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab_full replica &lt;span style="color:#66d9ef"&gt;identity&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;full&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; ctid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;(0,2)&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--复制标识设置为full后，删除成功
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DELETE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; ctid,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full ; &lt;span style="color:#75715e"&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tab_full &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; ctid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;(0,5)&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; ctid,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlbd&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; ctid,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab_full ; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&amp;ndash;这个例子可以证明3个点&lt;/p&gt;
&lt;p&gt;&amp;ndash;1.当复制标识为d(default)时，默认用主键，如果没有主键就是nothing&lt;/p&gt;
&lt;p&gt;&amp;ndash;2.nothing不能复制delete和update&lt;/p&gt;
&lt;p&gt;&amp;ndash;3.full时的重复数据也可以正常逻辑复制，虽然数据行的ctid不一样，但是也达到了复制目的&lt;/p&gt;

&lt;h3 class="relative group"&gt;第三方同步软件
 &lt;div id="第三方同步软件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%ac%ac%e4%b8%89%e6%96%b9%e5%90%8c%e6%ad%a5%e8%bd%af%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;第三方同步软件已经有比较成熟的方案，而且使用比较多，比如ogg、dts、ktl等等&lt;/p&gt;
&lt;p&gt;这些同步软件非常灵活，他们可以实现真正的异构同步，可以从pg库同步到不同的数据库或者kafka、大数据消费平台等等。&lt;/p&gt;
&lt;p&gt;当然也可以从其他架构的数据平台同步到pg库里，比如如今场景比较多的oracle到pg的同步。&lt;/p&gt;
&lt;p&gt;因为我们这里主要讨论pg数据库本身，当pg充当下游入库时，只是一些数据写入问题，问题非常少，不会有逻辑解析、复制槽等等问题，所以这一小章节不讨论pg作为异构同步下游的情况，只观察和总结pg作为上游往异构数据库同步的场景。这些第三方软件一般都利用了pg自身的逻辑解析，自行指定outputplugin并自动创建复制槽和复制链路，有些软件自动创建了订阅，而有些就没有订阅只有复制槽。&lt;/p&gt;
&lt;p&gt;前面已经了解了逻辑解析、outputplugin、复制槽、replicaidentity、复制的前置条件等知识点，下面模拟一个pg到oracle的同步，直接将前置条件配置好开始同步。&lt;/p&gt;

&lt;h4 class="relative group"&gt;创建ogg同步pg到oracle的同步
 &lt;div id="创建ogg同步pg到oracle的同步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%baogg%e5%90%8c%e6%ad%a5pg%e5%88%b0oracle%e7%9a%84%e5%90%8c%e6%ad%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;安装软件：&lt;/p&gt;
&lt;p&gt;ogg for oracle：Oracle GoldenGate 21.3.0.0.0 for Oracle on Linux x86-64&lt;/p&gt;
&lt;p&gt;ogg for pg ：Oracle GoldenGate 21.3.0.0.0 for PostgreSQL on Linux x86-64&lt;/p&gt;
&lt;p&gt;oracle ：11.2.0.4&lt;/p&gt;
&lt;p&gt;pg ：13.10&lt;/p&gt;
&lt;p&gt;安装步骤：&lt;/p&gt;
&lt;p&gt;ogg的安装和部署就不介绍了，我也是参照文章的安装步骤一步步搭建，安装文章参考：&lt;a href="https://liuzhilong.blog.csdn.net/article/details/129252320?spm=1001.2014.3001.5502" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net/article/details/129252320?spm=1001.2014.3001.5502&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同步架构图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/af57ae30ee4a.png" alt="c8be5aae99704448a8a7e2e01fbde05b.png" /&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_replication_slots &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; slot_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ext_pg_5d4b1d39f7494f79&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;[ RECORD &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ]&lt;span style="color:#75715e"&gt;-------+------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ext_pg_5d4b1d39f7494f79
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plugin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; test_decoding &lt;span style="color:#75715e"&gt;--ogg默认使用test-decoding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;slot_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; logical
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;datoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16385&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;temporary&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t &lt;span style="color:#75715e"&gt;--只要ogg extract是running的，复制槽就是active状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;active_pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3509&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;catalog_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;591&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;restart_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;F3E38
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirmed_flush_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;F4020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_status &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reserved
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;safe_wal_size &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_replication
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;[ RECORD &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; ]&lt;span style="color:#75715e"&gt;----+------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3509&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;usesysid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;application_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt;GoldenGateCapture
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_addr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;127&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_hostname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_port &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;43665&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;350469&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; streaming
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sent_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;F4140
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;write_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;F4020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;flush_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;F4020
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replay_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;write_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;flush_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replay_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sync_priority &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sync_state &lt;span style="color:#f92672"&gt;|&lt;/span&gt; async
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reply_time &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;986625&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--replay_lsn没有值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--连lag都没有值&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;逻辑复制监控
 &lt;div id="逻辑复制监控" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e7%9b%91%e6%8e%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;逻辑复制延迟监控有一个重要的手段是从复制软件看延迟。如果没有就只有从复制槽视图查看，复制槽视图的信息是比较多的，比如复制槽是否active就直接代表了复制链路是否在同步。&lt;/p&gt;
&lt;p&gt;复制槽视图对于逻辑复制监控非常重要，发布订阅的一些额外监控前面已介绍过，这里着重介绍宽泛的逻辑复制的监控&lt;/p&gt;

&lt;h4 class="relative group"&gt;pg_replication_slots
 &lt;div id="pg_replication_slots" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_replication_slots" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;复制槽视图，每个复制槽的信息和一些复制槽状态。手工创建复制槽或者工具、订阅自动创建了复制槽，都会在这里展示&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;slot_name&lt;/th&gt;
 &lt;th&gt;复制槽名&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;plugin&lt;/td&gt;
 &lt;td&gt;逻辑复制槽output plugin的名字，如果是空那么就是物理复制槽&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;slot_type&lt;/td&gt;
 &lt;td&gt;physical or logical&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;datoid&lt;/td&gt;
 &lt;td&gt;逻辑复制槽的database id&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;database&lt;/td&gt;
 &lt;td&gt;逻辑复制槽的database&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;temporary&lt;/td&gt;
 &lt;td&gt;是否是临时复制槽。临时复制槽不会写到磁盘，会话结束临时复制槽自动删除。pg_basebackup默认使用的就是临时复制槽&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;active&lt;/td&gt;
 &lt;td&gt;复制槽状态 t or f。如果是f，需要尽快考虑把复制链路拉起或者删除，因为可能阻碍wal日志删除导致主库磁盘打满，这个跟参数max_slot_wal_keep_size相关&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;active_pid&lt;/td&gt;
 &lt;td&gt;使用复制槽的walsender pid。当复制槽状态是t的时候，才有walsender pid&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;xmin&lt;/td&gt;
 &lt;td&gt;复制槽需要持有的最小事务id&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;catalog_xmin&lt;/td&gt;
 &lt;td&gt;复制槽需要持有的catalog最小事务id&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;restart_lsn&lt;/td&gt;
 &lt;td&gt;slot需要保留的wal的位置lsn号，以确保下游消费端需要的wal不会被清理。max_slot_wal_keep_size 参数是slot需要保留wal的最大大小，超过这个值wal也能被删除，默认值-1表示不会清理。 			这个值表示下游最新checkpoint消费后的lsn位置，可以帮助定位复制链路的延迟&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;confirmed_flush_lsn&lt;/td&gt;
 &lt;td&gt;逻辑复制下游确认接收的lsn。物理复制槽为空&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;wal_status&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;被这个复制槽申明的wal的状态&lt;/code&gt; 			 			reserved 代表复制槽保留了wal，wal没有超过max_wal_size(自动检查点间距） 			extended 代表复制槽保留了wal，wal超过了max_wal_size，但是复制槽仍保留了wal。此状态的wal仍在wal_keep_size或max_slot_wal_keep_size内 			unreserved 复制槽不再保留需要wal，在下个checkpoint即将删除wal 			lost 复制槽需要的wal已被清理，复制槽已无效 		 			&lt;code&gt;The last two states are seen only when max_slot_wal_keep_size is non-negative。比较好理解，毕竟max_slot_wal_keep_size是判断是否可以删除wal的标准。如果没有删除slot wal的机制，那就不会出现ureserved和lost两种状态。&lt;/code&gt; 			&lt;code&gt;If restart_lsn is NULL, this field is null.也比较好理解，如果wal的lsn都没有就不知道wal保留的位置，也无法判断wal是否超过了wal_keep_size或max_slot_wal_keep_size&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;safe_wal_size&lt;/td&gt;
 &lt;td&gt;到在被删除WAL文件之前，可以写入的WAL字节数。如果这个值是负数或者是0，意味着已经超过了max_slot_wal_keep_size设置的值，只要做检查点，就会删除wal文件，这样使用插槽的备库就必须重建了&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;pg_stat_replication
 &lt;div id="pg_stat_replication" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_stat_replication" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;与其说是复制状态，其实walsender状态更准确。该视图展示每个walsender的状态，一个walsender一条记录。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果pg_replication_slots中有而pg_stat_replication中没有，那么说明walsender不在了，逻辑复制挂了，pg_replication_slots active应该是f&lt;/li&gt;
&lt;li&gt;如果pg_replication_slots中没有而pg_stat_replication中有，那么说明这是个不带复制槽的物理复制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;没有复制槽也可以有replicationstat信息，有walsender的复制槽也需看该视图，因为该视图比pg_replication_slots揭示更多复制状态信息&lt;/p&gt;
&lt;p&gt;所以当复制槽没有挂时，pg_stat_replication对于监控逻辑复制延迟非常重要&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;pid&lt;/th&gt;
 &lt;th&gt;walsender pid ，同pg_replication_slotsactive_pid&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;usesysid&lt;/td&gt;
 &lt;td&gt;连入这个walsender的user oid，也就是下游使用的复制用户oid&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;usename&lt;/td&gt;
 &lt;td&gt;连入这个walsender的usename&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;application_name&lt;/td&gt;
 &lt;td&gt;下游的的应用程序名称。如果是订阅，那么就是订阅名。如果是pg_recvlogical就是pg_recvlogical&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;client_addr&lt;/td&gt;
 &lt;td&gt;下游的IP，如果是空就是本地socket连接&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;client_hostname&lt;/td&gt;
 &lt;td&gt;下游的主机名&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;client_port&lt;/td&gt;
 &lt;td&gt;下游的端口，如果是-1就是本地socket连接&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;backend_start&lt;/td&gt;
 &lt;td&gt;backend启动时间，也就是下游连入walsender的时间&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;backend_xmin&lt;/td&gt;
 &lt;td&gt;hot_standby_feedback打开时，standby的xmin。这个明显是物理复制的&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;state&lt;/td&gt;
 &lt;td&gt;状态比较简单易懂 			 			 			 				startup: walsender正在启动 				catchup: walsender正在追主库日志 				streaming: walsender已经追上了主库日志，正常复制状态 				backup: walsender在发送备份，这个状态出现在备份使用的walsender 				stopping: walsender正在停止&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sent_lsn&lt;/td&gt;
 &lt;td&gt;发送的lsn&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;write_lsn&lt;/td&gt;
 &lt;td&gt;下游write到磁盘的lsn&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;flush_lsn&lt;/td&gt;
 &lt;td&gt;下游flush到磁盘的lsn&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;replay_lsn&lt;/td&gt;
 &lt;td&gt;下游重放的lsn&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;write_lag&lt;/td&gt;
 &lt;td&gt;主库flush wal和下游write之间的日志lag&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;flush_lag&lt;/td&gt;
 &lt;td&gt;主库flush wal和下游flush之间的日志lag&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;replay_lag&lt;/td&gt;
 &lt;td&gt;主库flush wal和下游relay之间的日志lag&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sync_priority&lt;/td&gt;
 &lt;td&gt;同步优先级&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sync_state&lt;/td&gt;
 &lt;td&gt;同步状态&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;reply_time&lt;/td&gt;
 &lt;td&gt;上次答复时间&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;sent_lsn、write_lsn、flush_lsn、replay_lsn的关系
 &lt;div id="sent_lsnwrite_lsnflush_lsnreplay_lsn的关系" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sent_lsnwrite_lsnflush_lsnreplay_lsn%e7%9a%84%e5%85%b3%e7%b3%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/08ab66a5cd02.png" alt="f2a89e2dabf84e0794c1a5854bb2006f.png" /&gt;&lt;/p&gt;
&lt;p&gt;上面很好的展示了sent_lsn、write_lsn、flush_lsn的层级关系&lt;/p&gt;
&lt;p&gt;这些监控指标看上去很像流复制的，对于逻辑复制来说sent_lsn、write_lsn、flush_lsn也一般都有值&lt;/p&gt;
&lt;p&gt;但是在逻辑复制不清楚下游是什么东西的情况下，replay这个日志回放动作可能是没有的，所以逻辑复制可能没有replay_lsn&lt;/p&gt;
&lt;p&gt;但是有一个东西是确认有效的，就是sent_lsn&lt;/p&gt;
&lt;p&gt;看完pg_replication_slots和pg_stat_replication视图监控，发现都没有展示日志解析延迟，最多只能看到日志传输延迟&lt;/p&gt;

&lt;h4 class="relative group"&gt;pg_stat_replication_slots
 &lt;div id="pg_stat_replication_slots" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_stat_replication_slots" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;这个视图从pg14开始才有，这个视图专门监控逻辑复制槽状态，可以额外监控spill的状态。pg13只有查看pg_replslot目录。spill后面会介绍&lt;/p&gt;

&lt;h3 class="relative group"&gt;逻辑复制槽的事务快照和pg_logical目录
 &lt;div id="逻辑复制槽的事务快照和pg_logical目录" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e6%a7%bd%e7%9a%84%e4%ba%8b%e5%8a%a1%e5%bf%ab%e7%85%a7%e5%92%8cpg_logical%e7%9b%ae%e5%bd%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;复制槽所需的事物快照会持久化到磁盘，源码在snapbuild.c中&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SnapBuildSerializationPoint&lt;/span&gt;(SnapBuild &lt;span style="color:#f92672"&gt;*&lt;/span&gt;builder, XLogRecPtr lsn)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (builder&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; SNAPBUILD_CONSISTENT)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SnapBuildRestore&lt;/span&gt;(builder, lsn);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SnapBuildSerialize&lt;/span&gt;(builder, lsn);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;snap持久化有2种行为：一种是restore从磁盘加载到内存，一种是serialize从内存持久化到磁盘&lt;/p&gt;
&lt;p&gt;事物快照持久化：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SnapBuildSerialize&lt;/span&gt;(SnapBuild &lt;span style="color:#f92672"&gt;*&lt;/span&gt;builder, XLogRecPtr lsn)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sprintf&lt;/span&gt;(path, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_logical/snapshots/%X-%X.snap&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(uint32) (lsn &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;), (uint32) lsn);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (ret &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * somebody else has already serialized to this point, don&amp;#39;t overwrite
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * but remember location, so we don&amp;#39;t need to read old data again.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * To be sure it has been synced to disk after the rename() from the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * tempfile filename to the real filename, we just repeat the fsync.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * That ought to be cheap because in most scenarios it should already
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * be safely on disk.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fsync_fname&lt;/span&gt;(path, false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fsync_fname&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_logical/snapshots&amp;#34;&lt;/span&gt;, true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;last_serialized_snapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; lsn;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; out;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;事物快照加载到内存：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (builder-&amp;gt;state == SNAPBUILD_CONSISTENT)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sprintf(path, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_logical/snapshots/%X-%X.snap&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(uint32) (lsn &amp;gt;&amp;gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;), (uint32) lsn);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;逻辑复制槽需要的事物在未提交以前，会将事物脏数据和未消费的数据存放在pg_logical/snapshots/ 下面。在提交数据或启动复制槽后交给reorderbuffer：或者清理复制槽后，数据被释放&lt;/p&gt;
&lt;p&gt;我的环境有一个长时间未启用的slot，它的restart_lsn为0/1776858&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; slot_name,plugin,slot_type,&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;,active,restart_lsn &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_replication_slots &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; slot_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;logical_test&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slot_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plugin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; slot_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; restart_lsn 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+---------------+-----------+----------+--------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logical_test &lt;span style="color:#f92672"&gt;|&lt;/span&gt; test_decoding &lt;span style="color:#f92672"&gt;|&lt;/span&gt; logical &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776858&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_logical/snapshots/下最旧的snapshot就是它&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl snapshots&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;144&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 20:410-1776858.snap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;144&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 20:44 0-1776900.snap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;144&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 20:45 0-1776938.snap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;删除不要的复制槽&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_drop_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_test&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;等了几分钟snap被删除&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;lzl snapshots]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776858.&lt;/span&gt;snap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls: cannot access &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1776858.&lt;/span&gt;snap: No such file or directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;逻辑解析工作内存和溢出到pg_replslot
 &lt;div id="逻辑解析工作内存和溢出到pg_replslot" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90%e5%b7%a5%e4%bd%9c%e5%86%85%e5%ad%98%e5%92%8c%e6%ba%a2%e5%87%ba%e5%88%b0pg_replslot" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;logical_decoding_work_mem
 &lt;div id="logical_decoding_work_mem" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#logical_decoding_work_mem" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg13以前，逻辑解析的最多会在内存中保留4096条变更（max_changes_in_memory代码中写死），超过4096条变更，事务数据会写入磁盘&lt;/p&gt;
&lt;p&gt;pg13引入参数logical_decoding_work_mem。逻辑解析使用的工作内存，所有walsender解析都会使用这个共享内存区。如果逻辑解析持有的数据大过该内存值，会写入磁盘。逻辑解析工作内存大小默认64m。&lt;/p&gt;

&lt;h4 class="relative group"&gt;相关reorderbuffer和溢出
 &lt;div id="相关reorderbuffer和溢出" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%9b%b8%e5%85%b3reorderbuffer%e5%92%8c%e6%ba%a2%e5%87%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;reorderbuffer.c中的描述&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; This module gets handed individual pieces of transactions in the order
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; toplevel transaction sized pieces. When a transaction is completely
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; reassembled &lt;span style="color:#f92672"&gt;-&lt;/span&gt; signaled by reading the transaction commit record &lt;span style="color:#f92672"&gt;-&lt;/span&gt; it
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; will then call the output &lt;span style="color:#a6e22e"&gt;plugin&lt;/span&gt; (cf. &lt;span style="color:#a6e22e"&gt;ReorderBufferCommit&lt;/span&gt;()) with the
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; individual changes. The output plugins rely on snapshots built by
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; snapbuild.c which hands them to us.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当事务提交后，reorderbuffer能接收事务条目并排序，并把数据变更发给outputplugin输出。output plugin依赖于snapbuild.c构建的快照，快照交给reorderbuffer&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Maximum number of changes kept in memory, per transaction. After that,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * changes are spooled to disk.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * The current value should be sufficient to decode the entire transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * without hitting disk in OLTP workloads, while starting to spool to disk in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * other workloads reasonably fast.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * At some point in the future it probably makes sense to have a more elaborate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * resource management here, but it&amp;#39;s not entirely clear what that would look
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * like.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; logical_decoding_work_mem;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; Size max_changes_in_memory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* XXX for restore only */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;解析数据超过logical_decoding_work_mem后写入磁盘，max_changes_in_memory为写死的4096，现在只用作触发磁盘恢复restore。在pg12源码里面没有intlogical_decoding_work_mem,后面的serialization也是根据max_changes_in_memory来判断的。
pg13里面Disk serialization源码从2333行开始
当内存中的解析的数据大于logical_decoding_work_mem时，把最大的那个事务spill到磁盘
ReorderBufferLargestTXN(rb)找到那个最大的事务 ReorderBufferSerializeTXN(rb, txn);将这个事务持久化`
紧接着的代码就是ReorderBufferSerializeTXN()&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Spill data of a large transaction (and its subtransactions) to disk.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferSerializeTXN&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb, ReorderBufferTXN &lt;span style="color:#f92672"&gt;*&lt;/span&gt;txn)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dlist_iter subtxn_i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dlist_mutable_iter change_i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogSegNo curOpenSegNo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size spilled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;elog&lt;/span&gt;(DEBUG2, &lt;span style="color:#e6db74"&gt;&amp;#34;spill %u changes in XID %u to disk&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (uint32) txn&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nentries_mem, txn&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* do the same to all child TXs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在debug2级别，输出spill日志&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Given a replication slot, transaction ID and segment number, fill in the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * corresponding spill file into &amp;#39;path&amp;#39;, which is a caller-owned buffer of size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * at least MAXPGPATH.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferSerializedPath&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;path, ReplicationSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;slot, TransactionId xid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogSegNo segno)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogRecPtr recptr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;XLogSegNoOffsetToRecPtr&lt;/span&gt;(segno, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, wal_segment_size, recptr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;snprintf&lt;/span&gt;(path, MAXPGPATH, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot/%s/xid-%u-lsn-%X-%X.spill&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;NameStr&lt;/span&gt;(MyReplicationSlot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.name),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (uint32) (recptr &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;), (uint32) recptr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;持久化到pg_replslot/复制槽名/xid-%u-lsn-%X-%X.spill&lt;/p&gt;
&lt;p&gt;同样的，除了serialize，还有restore&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Restore a number of changes spilled to disk back into memory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; Size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferRestoreChanges&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb, ReorderBufferTXN &lt;span style="color:#f92672"&gt;*&lt;/span&gt;txn,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TXNEntryFile &lt;span style="color:#f92672"&gt;*&lt;/span&gt;file, XLogSegNo &lt;span style="color:#f92672"&gt;*&lt;/span&gt;segno)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size restored &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogSegNo last_segno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (restored &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_changes_in_memory &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;segno &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; last_segno)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; readBytes;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ReorderBufferDiskChange &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ondisk;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Read the statically sized part of a change which has information
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * about the total size. If we couldn&amp;#39;t read a record, we&amp;#39;re at the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * end of this file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferSerializeReserve&lt;/span&gt;(rb, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(ReorderBufferDiskChange));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;readBytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FileRead&lt;/span&gt;(file&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;vfd, rb&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;outbuf,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(ReorderBufferDiskChange),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curOffset, WAIT_EVENT_REORDER_BUFFER_READ);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * ok, read a full change from disk, now restore it into proper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * in-memory format
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferRestoreChange&lt;/span&gt;(rb, txn, rb&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;outbuf);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;restored&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; restored;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ReorderBufferRestoreChanges()只是做了判断和循环(restored++),调用的是ReorderBufferRestoreChange()&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferRestoreChange&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb, ReorderBufferTXN &lt;span style="color:#f92672"&gt;*&lt;/span&gt;txn,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Update memory accounting for the restored change. We need to do this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * although we don&amp;#39;t check the memory limit when restoring the changes in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * this branch (we only do that when initially queueing the changes after
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * decoding), because we will release the changes later, and that will
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * update the accounting too (subtracting the size from the counters). And
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * we don&amp;#39;t want to underflow there.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferChangeMemoryUpdate&lt;/span&gt;(rb, change, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ReorderBufferChangeSize&lt;/span&gt;(change));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;看了眼ReorderBufferRestoreChanges()，它的while循环判断是restored &amp;lt; max_changes_in_memory，而restored的初始值为0，它会循环执行4096次。ReorderBufferRestoreChange中有段注释说明了，虽然restore不是根据memorylimit来判断的，但是仍要更新内存使用量，以防下溢。也就是说我才retore上来就别再套娃spill下去了
（感觉这有点怪，明显以memorylimit来判断更好，而不是写死restore循环次数）&lt;/p&gt;
&lt;p&gt;根据源码解读逻辑解析过程：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b6939610878b.png" alt="69b422c44d6d43e991eea0c8904e166c.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;xtransaction snap保留解析锁需要的元数据，复制槽处于非活动状态或事物未提交，snap仍然进行pg_logical/snapshots/%restart_lsn.snap，复制槽重新启动后或事物提交后，将磁盘上的事物snap元数据读到内存发送给reorderbuffer解析wal，以事物的开始执行顺序排序。如果逻辑解析数据将logical_decoding_work_mem内存区打满，变更条目会将最大的事物持久化到pg_replslot/复制槽名/xid-%u-lsn-%X-%X.spill，将其他的在内存中的事物发送给outputplugin转化输出格式，最后把解码后的信息发送给下游。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其实可以看出来，长事物和大事物可以将整个逻辑复制链路搞的很慢。大事务优先spill到磁盘，事务完成后又从磁盘加载到内存。&lt;/p&gt;

&lt;h3 class="relative group"&gt;总结
 &lt;div id="总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;逻辑复制通过复制槽管理，一个复制槽一个walsender进程，一个outputplugin&lt;/li&gt;
&lt;li&gt;output plugin决定了逻辑解析后的数据输出形态，在创建复制槽时指定&lt;/li&gt;
&lt;li&gt;复制标识replicaidentity建议优先:主键-&amp;gt;非空唯一索引-&amp;gt;full&lt;/li&gt;
&lt;li&gt;发布订阅模式是pg内置的逻辑复制，默认使用pgoutput。发布可以单独使用&lt;/li&gt;
&lt;li&gt;发布端进程是walsender，订阅端进程是worker。需要关注各自进程的参数&lt;/li&gt;
&lt;li&gt;逻辑复制第三方软件较多，他们一般都使用pg逻辑解析这套体系&lt;/li&gt;
&lt;li&gt;监控复制链路需要关注pg_replication_slots,pg_stat_replication&lt;/li&gt;
&lt;li&gt;pg_logical目录会存放事务解析的元数据snap，等待事务提交后解析&lt;/li&gt;
&lt;li&gt;pg_replslot目录会存放超过logical_decoding_work_mem的事物信息，称为spill&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;参考资料
 &lt;div id="参考资料" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;书：《postgreSQL实战》&lt;/p&gt;
&lt;p&gt;官方文档：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/logicaldecoding.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: Chapter 49. Logical Decoding&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/logicaldecoding-example.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: 49.1. Logical Decoding Examples&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/app-pgrecvlogical.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: pg_recvlogical&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/14/view-pg-replication-slots.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 14: 52.81. pg_replication_slots&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/13/runtime-config-replication.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 13: 19.6. Replication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/13/logicaldecoding-output-plugin.html#LOGICALDECODING-OUTPUT-PLUGIN-CALLBACKS" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 13: 48.6. Logical Decoding Output Plugins&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/logical-replication-publication.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: 31.1. Publication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/logical-replication-subscription.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: 31.2. Subscription&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/sql-createpublication.html" target="_blank" rel="noreferrer"&gt;PostgreSQL: Documentation: 15: CREATE PUBLICATION&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;超推荐的资料：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pgconf.asia/JA/2017/wp-content/uploads/sites/2/2017/12/D2-A7-EN.pdf" target="_blank" rel="noreferrer"&gt;https://www.pgconf.asia/JA/2017/wp-content/uploads/sites/2/2017/12/D2-A7-EN.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.anayrat.info/en/2018/03/10/logical-replication-internals/" target="_blank" rel="noreferrer"&gt;Logical replication internals | Select * from Adrien&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.highgo.ca/2019/08/22/an-overview-of-logical-replication-in-postgresql/" target="_blank" rel="noreferrer"&gt;An Overview of Logical Replication in PostgreSQL - Highgo Software Inc.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/4lF4LonDQeICPtbUX_HVnw" target="_blank" rel="noreferrer"&gt;从实际案例聊聊逻辑解码&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/yiukiiOa0snzcak1ThmP7Q" target="_blank" rel="noreferrer"&gt;折磨许久的逻辑解码异常&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cybertec-postgresql.com/en/monitoring-replication-pg_stat_replication/" target="_blank" rel="noreferrer"&gt;Monitoring replication: pg_stat_replication - CYBERTEC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其他资料：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zhuanlan.zhihu.com/p/311496301" target="_blank" rel="noreferrer"&gt;https://zhuanlan.zhihu.com/p/311496301&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dzone.com/articles/postgresql-change-data-capture" target="_blank" rel="noreferrer"&gt;A Guide to PostgreSQL Change Data Capture - DZone&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/change-data-capture-in-postgres-how-to-use-logical-decoding-and/ba-p/1396421" target="_blank" rel="noreferrer"&gt;Change data capture in Postgres: How to use logical decoding and wal2json - Microsoft Community Hub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.kancloud.cn/taobaomysql/monthly/213790" target="_blank" rel="noreferrer"&gt;PgSQL · PostgreSQL 逻辑流复制技术的秘密 · 数据库内核月报 · 看云&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/dafei1288/article/details/124629875" target="_blank" rel="noreferrer"&gt;剖析postgresql逻辑复制原理_postgresql 逻辑复制_麒思妙想的博客-CSDN博客&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://pigsty.cc/zh/blog/2021/03/03/postgres" target="_blank" rel="noreferrer"&gt;http://pigsty.cc/zh/blog/2021/03/03/postgres&lt;/a&gt;逻辑复制详解/&lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-logical" target="_blank" rel="noreferrer"&gt;Logical replication and logical decoding - Azure Database for PostgreSQL - Flexible Server | Microsoft Learn&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Linux内存浅析</title><link>https://lastdba.com/2024/08/12/linux%E5%86%85%E5%AD%98%E6%B5%85%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/linux%E5%86%85%E5%AD%98%E6%B5%85%E6%9E%90/</guid><description>&lt;h2 class="relative group"&gt;内存的基本概念
 &lt;div id="内存的基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;操作系统内存非常重要且比较复杂，其中有许多知识点仍然需要掌握才能更进一步分析程序问题。由于是初次全面系统地接触OS内存，目的是为了全面且低层次地理解linux内存相关概念，不会深入其中原理，所以本章也会尽量避免linux的源码知识。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;内存的基本概念
 &lt;div id="内存的基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;操作系统内存非常重要且比较复杂，其中有许多知识点仍然需要掌握才能更进一步分析程序问题。由于是初次全面系统地接触OS内存，目的是为了全面且低层次地理解linux内存相关概念，不会深入其中原理，所以本章也会尽量避免linux的源码知识。&lt;/p&gt;

&lt;h3 class="relative group"&gt;物理内存和虚拟内存
 &lt;div id="物理内存和虚拟内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%89%a9%e7%90%86%e5%86%85%e5%ad%98%e5%92%8c%e8%99%9a%e6%8b%9f%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e9d3726e966d.png" alt="在这里插入图片描述" /&gt;
(&lt;a href="https://en.wikipedia.org/wiki/Memory_address" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Memory_address&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;物理内存（Physical memory）&lt;/strong&gt;：物理内存是计算机系统中实际存在的硬件内存，通常是RAM（随机存取存储器）的形式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;虚拟内存（Virtual memory）&lt;/strong&gt;：虚拟内存是一个线性区，并没有分配实际物理内存，程序认为它们有比实际物理内存更大的地址空间。虚拟内存的实现允许程序访问比物理内存更大的地址范围，而不需要所有数据都同时存在于物理内存中。内核释放物理页面是通过释放线性区，找到其所对应的物理页面，将其全部释放的过程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内存管理单元（Memory Management Unit，MMU）&lt;/strong&gt;：是一个硬件组件，负责将程序中使用的虚拟地址转换为实际在物理内存中存储数据的物理地址。MMU的主要任务是执行地址映射。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;页表（Page Table）&lt;/strong&gt;：页表是一种数据结构，用于存储虚拟地址空间与物理地址空间之间的映射关系。程序试图访问虚拟内存时，MMU通过查询页表确定相应的物理地址。&lt;/p&gt;
&lt;p&gt;系统调用流程：



&lt;img src="https://lastdba.com/img/csdn/b1b0da7b7d74.png" alt="在这里插入图片描述" /&gt;
&lt;a href="https://users.cs.utah.edu/~aburtsev/cs5460/lectures/lecture19-memory-management/lecture19-memory-management.pdf" target="_blank" rel="noreferrer"&gt;https://users.cs.utah.edu/~aburtsev/cs5460/lectures/lecture19-memory-management/lecture19-memory-management.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;（图有点糊，最上面的字是 “User Space|Kernel Space”）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用户程序通过C库或通过系统调用才能访问内核系统，用户程序不能直接访问内核系统&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内核系统通过MMU访问物理内存；通过驱动访问磁盘其他外部设备&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;虚拟内存系统（上图中的VM Subsystem）中包含buddy、slab算法等&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;用户空间和内核空间
 &lt;div id="用户空间和内核空间" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%94%a8%e6%88%b7%e7%a9%ba%e9%97%b4%e5%92%8c%e5%86%85%e6%a0%b8%e7%a9%ba%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;进程虚拟地址空间分成了用户空间和内核空间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;用户空间&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户进程在内存中运行的空间&lt;/li&gt;
&lt;li&gt;这部分空间被保护，系统防止其他进程访问。（共享内存除外）&lt;/li&gt;
&lt;li&gt;但是内核进程可以直接访问用户进程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;内核空间&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内核空间是内核进程使用的空间&lt;/li&gt;
&lt;li&gt;在内核空间，运行操作系统的内核代码，这些代码具有更高的特权级别，可以直接访问系统硬件、管理进程、进行文件系统操作等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;上下文切换：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当用户程序需要访问系统服务或执行需要更高权限的操作时，会触发从用户空间到内核空间的上下文切换。&lt;/li&gt;
&lt;li&gt;上下文切换是一种操作系统机制，用于保存和恢复程序的状态，确保在用户程序和内核之间切换时不会发生数据丢失。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用户空间和内核空间的划分是为了提供安全隔离，防止用户程序直接影响操作系统的关键部分。早期的操作系统和Dos系统不区分内核、用户空间，一个程序的错误或恶意行为可能对整个系统造成影响。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4b446b757f77.png" alt="在这里插入图片描述" /&gt;
(&lt;a href="https://www.zhihu.com/tardis/zm/art/66794639?source_id=1003" target="_blank" rel="noreferrer"&gt;https://www.zhihu.com/tardis/zm/art/66794639?source_id=1003&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;32位系统：总共4GB地址空间，3G UserSpace|1G KernelSpace&lt;/p&gt;
&lt;p&gt;64位系统：总共256TB地址空间，128T UserSpace|128T KernelSpace&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2^32=4GB，2^64=16777216TB，为什么是64位的系统是256TB地址空间呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/64-bit_computing" target="_blank" rel="noreferrer"&gt;64-bit computing wiki&lt;/a&gt;上有解释。简而言之，256TB (256 × 1024^4 bytes) 的内存地址足够了，目前以及能想象的未来还不会出现16EB (16 × 1024^6 bytes)的内存。&lt;/p&gt;

&lt;h3 class="relative group"&gt;进程虚拟地址空间
 &lt;div id="进程虚拟地址空间" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%9b%e7%a8%8b%e8%99%9a%e6%8b%9f%e5%9c%b0%e5%9d%80%e7%a9%ba%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;每个进程通常都有自己的独立虚拟内存空间。虚拟内存是一种抽象概念，为每个运行的进程提供了似乎是连续且私有的地址空间，使得每个进程都感觉自己拥有整个计算机系统的全部内存。&lt;/p&gt;
&lt;p&gt;进程虚拟地址空间分布：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/94df008e9d4a.png" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2bc35848088f.png" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.sohu.com/a/392831824_467784）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mmap 映射区域至顶向下扩展，mmap 映射区域和堆相对扩展，直至耗尽虚拟地址空间中的剩余区域，这种结构便于C运行时库使用mmap 映射区域和堆进行内存分配。&lt;/li&gt;
&lt;li&gt;栈区(Stack)：存储程序执行期间的本地变量和函数的参数，从高地址向低地址生长&lt;/li&gt;
&lt;li&gt;堆区(Heap)：动态内存分配区域，通过 malloc、new、free 和delete 等函数管理&lt;/li&gt;
&lt;li&gt;未初始化变量区(BSS)：存储未被初始化的全局变量和静态变量&lt;/li&gt;
&lt;li&gt;数据区(Data)：存储在源代码中有预定义值的全局变量和静态变量&lt;/li&gt;
&lt;li&gt;代码区(Text)： 存储只读的程序执行代码，即机器指令。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;进程虚拟地址空间分布和映射：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/92827b8dcc73.png" alt="在这里插入图片描述" /&gt;
(&lt;a href="https://velog.io/@mysprtlty/%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%99%80-%EA%B0%80%EC%83%81-%EC%A3%BC%EC%86%8C-%EA%B3%B5%EA%B0%84" target="_blank" rel="noreferrer"&gt;https://velog.io/@mysprtlty/%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%99%80-%EA%B0%80%EC%83%81-%EC%A3%BC%EC%86%8C-%EA%B3%B5%EA%B0%84&lt;/a&gt;)&lt;/p&gt;

&lt;h3 class="relative group"&gt;共享内存
 &lt;div id="共享内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;前面讲到，虚拟地址空间中的用户空间不能被其他用户进程访问，如果通过内核区域实现多进程的用户访问同一内存数据，那么无法避免上下文切换。多进程的应用程序明显需要进程间的相互访问，所以一种直接可以实现用户进程访问同一物理内存的方法便应运而生，这就是共享内存。&lt;/p&gt;
&lt;p&gt;共享内存是实现进程相互访问IPC（inter process communication）的机制之一，其他的方式还有message queues和semaphores。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d969a23e8ba9.png" alt="在这里插入图片描述" /&gt;
（https://www.geeksforgeeks.org/inter-process-communication-ipc/）&lt;/p&gt;
&lt;p&gt;由于本身就是多个虚拟内存地址空间对应一个物理内存地址空间，所以只要把两个进程的地址空间中的一段指向同一物理内存即可。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/1bc1a1357c78.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.softprayog.in/programming/interprocess-communication-using-system-v-shared-memory-in-linux）&lt;/p&gt;
&lt;p&gt;共享内存（seems like）有许多实现方式，例如postgresql默认是mmap来实现共享内存，参考&lt;a href="https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-SHARED-MEMORY-TYPE" target="_blank" rel="noreferrer"&gt;shared_memory_type参数&lt;/a&gt;和&lt;a href="https://www.postgresql.org/docs/current/kernel-resources.html" target="_blank" rel="noreferrer"&gt;Managing Kernel Resources&lt;/a&gt;。其他的共享内存实现可参考这篇文章：&lt;a href="https://cloud.tencent.com/developer/article/1551288" target="_blank" rel="noreferrer"&gt;宋宝华：世上最好的共享内存(Linux共享内存最透彻的一篇)&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;页表 PAGE TABLE
 &lt;div id="页表-page-table" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%a1%b5%e8%a1%a8-page-table" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;进程虚拟地址空间是对于每个进程而言的，而物理内存空间只有一个。那么如果映射、转换虚拟内存和共享内存呢？&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/02d5376a22ed.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf" target="_blank" rel="noreferrer"&gt;https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;页表就是存储虚拟内存地址和物理内存地址的对应关系的地方&lt;/strong&gt;。(这里有内存管理单元MMU和转换缓冲区TLB等的概念，我们简化一下，简单理解为虚拟内存到物理内存转换功能（PAGING），这里只看页表）。一个页表是一组页表项page table entries (PTEs) 组成，PTE存储了虚拟页和物理页间的map。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/3e31e4f9f0eb.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;单个页表虽然可以实现内存到虚拟内存的转换功能，但是直接这样实现话，页表本身又占用了太多的内存。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4e25eb557be1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf" target="_blank" rel="noreferrer"&gt;https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;所以，需要对单个页表进行再分页：二级页表和四级页表&lt;/p&gt;
&lt;p&gt;二级页表：&lt;/p&gt;
&lt;p&gt;二级页表就是对单页表的再分页。4G 的空间需要 4M 的页表来存储映射表，如果将这 4M 分成 1K 个 页（4K）, 这 1K 个页也需要一个表进行管理，我们成为&lt;strong&gt;页目录表&lt;/strong&gt;，这个页目录表里面有 1K 项，每项 4 个字节，页目录表大小也就是 4K 。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/527ca245cbef.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;四级页表：&lt;/p&gt;
&lt;p&gt;对于 64 位系统，两级页表也不够，需要用四级页表&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/aec3c7ac7449.png" alt="在这里插入图片描述" /&gt;
（https://maodanp.github.io/2019/06/02/linux-virtual-space/）&lt;/p&gt;
&lt;p&gt;查看pagetable的大小：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl 2345&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat /proc/meminfo |grep PageTables
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PageTables: &lt;span style="color:#ae81ff"&gt;46736&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;NUMA
 &lt;div id="numa" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#numa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Uniform Memory Access (UMA)&lt;/strong&gt;：所有cpu访问内存的时间是等价的。UMA存在的问题是多个处理器通过一条总线访问内存，使共享总线上负载增加。多个处理器会争用memory controller造成冲突。另外总线带宽有限，会有访问延迟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Non-Uniform Memory Access (&lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/chap-virtualization_tuning_optimization_guide-numa" target="_blank" rel="noreferrer"&gt;NUMA&lt;/a&gt;)&lt;/strong&gt;：一小组CPU一起访问它们自己的本地内存。存在多组CPU和它们的内存组时，每组CPU和内存组就构成一个NUMA节点(node)。&lt;/p&gt;
&lt;p&gt;UMA：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8aa08bee1125.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;NUMA：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5c9b2c4ad417.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://users.cs.utah.edu/~aburtsev/cs5460/lectures/lecture19-memory-management/lecture19-memory-management.pdf）&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NUMA的基本特性&lt;/em&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cpu访问本地node的内存要比remote的更快&lt;/li&gt;
&lt;li&gt;默认情况下linux优先在cpu上分配本地内存，策略可以配置&lt;/li&gt;
&lt;li&gt;每个node都有自己的内存结构&lt;/li&gt;
&lt;li&gt;不是所有场景都适合numa，需要上层应用的适配&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;NUMA balancing&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;通过自动转移任务到远端cpu或者拷贝远端数据到本地内存的方式，实现本地访问。redhat 7上默认打开。&lt;/p&gt;
&lt;p&gt;转移任务或者拷贝数据本身也消耗资源，导致任务变慢，该特性可能不适用于部分应用，例如oracle的exdata就对NUMA做了针对优化。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;numactl&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;NUMA的OS配置工具 。&lt;/p&gt;
&lt;p&gt;numactl &amp;ndash;show检视cpu和node情况，如下为4node总共64c256g，每个node有16c64g：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;available: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; nodes &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0-3&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; cpus: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;33&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; size: &lt;span style="color:#ae81ff"&gt;65418&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; free: &lt;span style="color:#ae81ff"&gt;310&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; cpus: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;47&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; size: &lt;span style="color:#ae81ff"&gt;65536&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; free: &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; cpus: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;51&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;53&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; size: &lt;span style="color:#ae81ff"&gt;65536&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; free: &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; cpus: &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;58&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; size: &lt;span style="color:#ae81ff"&gt;65536&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; free: &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; MB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;zone
 &lt;div id="zone" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#zone" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;NUMA把cpus和内存分成多个node（node 0，node 1，node 2 ···），UMA结构中也可以把cpu内存整体看成node 0。&lt;/p&gt;
&lt;p&gt;在Linux中每个node用数据结构&lt;code&gt;struct pglist_data&lt;/code&gt;表示，数据类型为&lt;code&gt;typedef pg_data_t&lt;/code&gt;。每个node又分为多个zone，一个zone的数据结构为&lt;code&gt;zone_t&lt;/code&gt;，数据类型为&lt;code&gt;zone_struct&lt;/code&gt;，一般有3种数据类型&lt;code&gt;ZONE_DMA&lt;/code&gt;, &lt;code&gt;ZONE_NORMAL&lt;/code&gt; , &lt;code&gt;ZONE_HIGHMEM&lt;/code&gt;，每个类型的zone有各种不同的功能。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8507ec262240.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.kernel.org/doc/gorman/html/understand/understand005.html）&lt;/p&gt;
&lt;p&gt;32位zone的区域分布及功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ZONE_DMA&lt;/code&gt;：(&amp;lt;16MB)，&lt;em&gt;Direct Memory Access&lt;/em&gt; (DMA)，古老的16 MiB限制，包含&lt;a href="https://en.wikipedia.org/wiki/Industry_Standard_Architecture" target="_blank" rel="noreferrer"&gt;ISA devices&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ZONE_DMA32&lt;/code&gt;：由于很多设备在访问无法用 32 位寻址的内存时遇到问题，在x86-64新增了这样一个区域，该区域只存在于x86-64架构中。（详见&lt;a href="https://lwn.net/Articles/152462/" target="_blank" rel="noreferrer"&gt;ZONE_DMA32&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ZONE_NORMAL&lt;/code&gt;： (16MB to 896MB)，可直接映射到内核段的普通内存域；大部分内核操作都在NORMAL区进行，这是最重要的一个区域&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ZONE_HIGHMEM&lt;/code&gt;：(&amp;gt;896MB)，标记了超出内核段的物理内存，不能直接被内核调用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;32位和64位的zone分布图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/13284b0811ff.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://users.cs.utah.edu/~aburtsev/cs5460/lectures/lecture19-memory-management/lecture19-memory-management.pdf" target="_blank" rel="noreferrer"&gt;https://users.cs.utah.edu/~aburtsev/cs5460/lectures/lecture19-memory-management/lecture19-memory-management.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;注意zone是对于物理内存而言的，虚拟内存的用户态转换为内核态后，才可以调用物理内存。下图便是虚拟内存空间的内核地址与物理地址空间中的zone的关系：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0f0adc123018.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://wr.informatik.uni-hamburg.de/_media/teaching/wintersemester_2014_2015/kp-1415-memory-management.pdf）&lt;/p&gt;
&lt;p&gt;检视zone：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cat /proc/zoneinfo&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cat /proc/buddyinfo&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt; cat /proc/pagetypeinfo&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/buddyinfo 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA32 &lt;span style="color:#ae81ff"&gt;688&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2080&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1420&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;995&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;596&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;357&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;278&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;241&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;276&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;133&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal &lt;span style="color:#ae81ff"&gt;195748&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;204074&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;161167&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;119070&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;70791&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;33578&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9556&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2070&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1034&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2533&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7328&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 1, zone Normal &lt;span style="color:#ae81ff"&gt;11705&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;51467&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36752&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21326&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11343&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7309&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5024&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3403&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2597&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3056&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10898&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;页
 &lt;div id="页" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%a1%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;虚拟内存和物理内存被分割为固定大小的片段，一般是4KB大小。所以虚拟内存分割后就有了虚拟页，物理内存分割后就有了物理页（PP or PF，Physical Page or Page Frame），物理页也叫页帧，也是4KB。页帧代表系统内存的最小单位。&lt;/p&gt;
&lt;p&gt;虚拟地址空间的每个页面都可以通过其描述项对应到物理地址空间的一个页帧上。&lt;/p&gt;

&lt;h3 class="relative group"&gt;Huge Pages/Transparent Huge Pages
 &lt;div id="huge-pagestransparent-huge-pages" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#huge-pagestransparent-huge-pages" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;页是内存分配的最小单元（默认4K），当map分配大量的连续页时性能较差，&lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/s-memory-transhuge" target="_blank" rel="noreferrer"&gt;Huge Page&lt;/a&gt;就是为了解决这个问题。大页不仅分配的时候更cheap，页表同时也相对会更小。hugepagesz 为2 MB或1 GB，默认是2MB。REDHAT 6开始实现了Huge Page。&lt;/p&gt;
&lt;p&gt;由于手动管理大页比较麻烦，REDHAT 6开始同样也提供了自动管理大页的功能，即&lt;strong&gt;透明大页&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在oracle的数据库管理中，一般把大页打开给SGA使用，透明大页关闭。相关资料也比较多可行搜索资料。&lt;/p&gt;
&lt;p&gt;同样的，PostgreSQL也可以开启大页。由于数据库一般会占用较多的操作系统内存，数据库开启大页一般可以降低内存分配的压力。&lt;/p&gt;

&lt;h3 class="relative group"&gt;文件页与PageCache/匿名页与SwapCache
 &lt;div id="文件页与pagecache匿名页与swapcache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%96%87%e4%bb%b6%e9%a1%b5%e4%b8%8epagecache%e5%8c%bf%e5%90%8d%e9%a1%b5%e4%b8%8eswapcache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;文件页可以map到磁盘上的文件，文件系统的读写会通过Page Cache当做缓存IO，脏数据周期或被调用时“sync”（or fsync之类的）到对应的磁盘，Page Cache就是用来“提升”磁盘性能的内存区域。&lt;/p&gt;
&lt;p&gt;相对应的，没有文件相关联的页叫匿名页（Anonymous pages ），一般对应着heap、stack。当内存资源紧张时，内核会把不经常使用的匿名页中的数据写入到 Swap 分区或者 Swap 文件中。&lt;/p&gt;
&lt;p&gt;简而言之：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;page cache是与文件映射对应;&lt;/li&gt;
&lt;li&gt;swap cache是与匿名页对应&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/cc6be7d9bb51.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.slideshare.net/raghusiddarth/memory-management-in-linux-11551521?from_search=2）&lt;/p&gt;
&lt;p&gt;以上page cache的图是站在操作系统的角度来看的，应用程序（如数据库）的写入也可以不delayed，甚至不通过Page cache。&lt;/p&gt;

&lt;h2 class="relative group"&gt;内存分配
 &lt;div id="内存分配" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%88%86%e9%85%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;内存分配也十分复杂，涉及很多概念。两种常见的内存分配方式为buddy、slab&lt;/p&gt;

&lt;h3 class="relative group"&gt;buddy
 &lt;div id="buddy" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#buddy" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;buddy系统用于分配连续的内存页，每个zone都有各自的buddy系统。buddy系统划分了大块内存以响应内存分配请求，同时由于合并的特性可以减少系统内存碎片化。&lt;/p&gt;
&lt;p&gt;buddy allocator将内存分为2的幂次方的页，最大阶数为10：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/031369fb6ba0.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;当内存请求大于已有块的大小时，系统会将较大的块分割成两个相等大小的伙伴块。当内存释放时，系统会尝试将相邻的伙伴块合并成一个更大的块：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2eb819ac1f2d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;释放⻚⾯的时候就直接把⻚⾯放回空闲列表，如果其之前拆开的另⼀半⻚⾯也没有被分配，则组合成双倍⻚⾯交给更⼤的列表，然后依次循环，直到不能再循环或者已经到头。&lt;/p&gt;
&lt;p&gt;由于高阶页因为不停的分配没有了，此时再申请高阶页时便会触发碎片问题：



&lt;img src="https://lastdba.com/img/csdn/385e337b4093.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;等待内存回收成功后，buddy本身会合并低阶到高阶，然后分配高阶页面：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2452398bd6ce.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（The implementations of anti pages fragmentation in Linux kernel &lt;a href="https://teawater.github.io/presentation/antif.pdf" target="_blank" rel="noreferrer"&gt;https://teawater.github.io/presentation/antif.pdf&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;然而内存回收也可能赶不上分配速度，所以buddy系统不总是那么理想。&lt;/p&gt;
&lt;p&gt;分析示例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/buddyinfo 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA32 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;272&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal &lt;span style="color:#ae81ff"&gt;317681&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38869&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31620&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19250&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8931&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2579&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;815&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;182&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;上述包含3个ZONE：DMA，DMA32，Normal&lt;/li&gt;
&lt;li&gt;阶数： 0 ~ 10，即buddy里对应每一阶对应的数量。buddy最大的阶数为10, 即1024个pages，也就是4MB&lt;/li&gt;
&lt;li&gt;如Normal 行第3列表示有31620个2^2连续内存块可以用&lt;/li&gt;
&lt;li&gt;以此类推，越是往后的空间，就越是连续，数目越多，就代表这个大小的连续空间越多，当大的连续空间很少的时候，也就说明内存碎片已经不少&lt;/li&gt;
&lt;li&gt;另外，全部加起来就是当前free状态的内存&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过buddyinfo判断内存碎片问题：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#host 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal &lt;span style="color:#ae81ff"&gt;317681&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38869&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31620&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19250&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8931&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2579&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;815&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;182&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#host 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal &lt;span style="color:#ae81ff"&gt;7321&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7833&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10885&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8514&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2311&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1644&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1663&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1302&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1141&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7384&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80675&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面是两个主机的内存情况，对比可以发现，下面这个主机的连续内存更多，上面那个主机存在内存碎片问题。&lt;/p&gt;

&lt;h3 class="relative group"&gt;slab
 &lt;div id="slab" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#slab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;slab分配器是&lt;strong&gt;基于对象&lt;/strong&gt;进行管理的。slab系统是一种专门为&lt;strong&gt;内核&lt;/strong&gt;内存设计的内存分配算法。它通过将内存划分为固定大小的cache来实现，每个slab都包含同一类型的对象集。当有内存请求时，该算法首先检查适当的slab缓存中是否存在可用的对象。如果存在，则返回该对象。如果不存在，则算法会分配一个新的slab并将其添加到适当的cache中。&lt;/p&gt;
&lt;p&gt;不同大小的对象对应不同的slab cache：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6da00bf9a4b4.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf" target="_blank" rel="noreferrer"&gt;https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;虽然slab有不同的cache和对象，但是slab仍然使用的是物理连续的内存：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8274eb96e6d6.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://i.stack.imgur.com/wo8Gg.png）&lt;/p&gt;
&lt;p&gt;slab也有3种实现方式：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6c784e30b08b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;内存回收
 &lt;div id="内存回收" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%9b%9e%e6%94%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;推荐文章：&lt;a href="https://blog.csdn.net/weixin_35094083/article/details/116688112" target="_blank" rel="noreferrer"&gt;linux强制回收内存,linux内存源码分析 - 内存回收&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;内存回收概述
 &lt;div id="内存回收概述" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%9b%9e%e6%94%b6%e6%a6%82%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当系统内存压力具大时，就会对系统的每个压力大的zone进程内存回收，内存回收主要是针对匿名页和文件页进行；&lt;/li&gt;
&lt;li&gt;对于匿名页，内存回收过程中会筛选出一些不经常使用的匿名页，将它们写入到swap分区中，然后作为空闲页框释放到伙伴系统；&lt;/li&gt;
&lt;li&gt;对于文件页，内存回收过程中也会筛选出一些不经常使用的文件页：
&lt;ul&gt;
&lt;li&gt;如果此文件页中保存的内容与磁盘中文件对应内容一致，说明此文件页是一个干净的文件页，就不需要进行回写，直接将此页作为空闲页框释放到伙伴系统中；&lt;/li&gt;
&lt;li&gt;如果文件页保存的数据与磁盘中文件对应的数据不一致，则认定此文件页为脏页，需要先将此文件页回写到磁盘中对应数据所在位置上，然后再将此页作为空闲页框释放到伙伴系统中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内存回收完成后，系统空闲的页框数量就会增加，能够缓解内存压力，但在回收过程中会对系统的IO造成很大的压力，所以，在系统内，为每个zone会设置一条线，当空闲页框数量不满足这条线时，就会执行内存回收操作，而系统空闲页框数量满足这条线时，系统是不会进行内存回收操作的。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;zone的水位线与kswapd
 &lt;div id="zone的水位线与kswapd" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#zone%e7%9a%84%e6%b0%b4%e4%bd%8d%e7%ba%bf%e4%b8%8ekswapd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c611d500255d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://vivani.net/2022/06/14/linux-kernel-tuning-page-allocation-failure/)&lt;/p&gt;
&lt;p&gt;当可用内存较低时kswapd守护进程会被唤醒以释放页&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**pages_low:**当可用的空闲页面数量低于pages_low 时，buddy allocator会唤醒 **kswapd **进程，内核开始将页换出到硬盘。&lt;/li&gt;
&lt;li&gt;**pages_min:**当可用页面数量达到 pages_min时，说明页回收工作的压力就比较大，因为内存域中急需空闲页。分配器将以同步的方式执行 kswapd 工作，有时也称为直接回收。&lt;/li&gt;
&lt;li&gt;**pages_high:**一旦 kswapd 被唤醒开始释放页面，只有在可用页面数量达到pages_high时，内核才认为该区域是“平衡的”。如果水位线达到pages_high，kswapd 将重新进入休眠状态。空闲页多于pages_high，则内核认为zone的状态是理想的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内存回收以zone为单位进行，&lt;code&gt;/proc/zoneinfo&lt;/code&gt;可以查看min、low、high的值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vm.min_free_kbytes&lt;/code&gt;也就是min_pages线，十分重要的操作系统参数。非常低的值会阻止系统有效地回收内存，这可能会导致系统崩溃并中断服务。太高的值会增加系统回收活动，造成分配延迟，这可能导致系统立即进入内存不足状态。&lt;/p&gt;

&lt;h3 class="relative group"&gt;内存分配和回收的种类
 &lt;div id="内存分配和回收的种类" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%88%86%e9%85%8d%e5%92%8c%e5%9b%9e%e6%94%b6%e7%9a%84%e7%a7%8d%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;快速内存分配&lt;/strong&gt;：是get_page_from_freelist()函数，通过low阀值从zonelist中获取合适的zone进行分配，如果zone没有达到low阀值，则会进行快速内存回收，快速内存回收后再尝试分配。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;慢速内存分配&lt;/strong&gt;：当快速分配失败后，也就是zonelist中所有zone在快速分配中都没有获取到内存，则会使用min阀值进行慢速分配，在慢速分配过程中主要做三件事，异步内存压缩、直接内存回收以及轻同步内存压缩，最后视情况进行oom分配。并且在这些操作完成后，都会调用一次快速内存分配尝试获取页框。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/85d59cc1ec86.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://blog.csdn.net/weixin_35094083/article/details/116688112）&lt;/p&gt;
&lt;p&gt;不同的内存分配路径中，会触发不同的内存回收方式，对zone的内存回收方式分为两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;后台内存回收&lt;/strong&gt;（kswapd）：在物理内存紧张的时候，会唤醒 kswapd 内核线程来回收内存，这个回收内存的过程&lt;strong&gt;异步&lt;/strong&gt;的，不会阻塞进程的执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;直接内存回收&lt;/strong&gt;（direct reclaim）：如果后台异步回收跟不上进程内存申请的速度，就会开始直接回收，这个回收内存的过程是&lt;strong&gt;同步&lt;/strong&gt;的，会阻塞进程的执行。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;内存压缩
 &lt;div id="内存压缩" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%8e%8b%e7%bc%a9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;内存压缩见：内存的监控-/proc/pagetypeinfo部分&lt;/p&gt;

&lt;h3 class="relative group"&gt;LRU
 &lt;div id="lru" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lru" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;对于zone的内存回收，它针对三样东西进程回收：slab、lru链表中的页、buffer_head。这里只讨论内存回收针对lru链。&lt;/p&gt;
&lt;p&gt;lru链表主要作用就是将页排序，将最应该回收的页放到最后面，最不应该回收的页放到最前面，然后进行内存回收时，就会从后面向前面进行扫描，将扫描到的页尝试进行回收。&lt;/p&gt;
&lt;p&gt;lru链表描述符，里面有5个lru链表，活动/非活动匿名页lru链表，活动/非活动文件页lru链表，禁止换出页链表：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/958bc46a109a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://lpc.events/event/11/contributions/896/attachments/793/1493/slides-r2.pdf）&lt;/p&gt;
&lt;p&gt;内存回收来说，它只会处理前面4个lru链表，也就是活动匿名页lru链表，非活动匿名页lru链表，活动文件页lru链表，非活动文件页lru链。回收到足够页框后直接返回：快速内存回收、kswapd内存回收中会这样做。&lt;/p&gt;
&lt;p&gt;可以通过meminfo查看global lruvec（理解为lru区域）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## cat /proc/meminfo |grep -i active&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active: &lt;span style="color:#ae81ff"&gt;597380&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive: &lt;span style="color:#ae81ff"&gt;601920&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active&lt;span style="color:#f92672"&gt;(&lt;/span&gt;anon&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10896&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive&lt;span style="color:#f92672"&gt;(&lt;/span&gt;anon&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;117376&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active&lt;span style="color:#f92672"&gt;(&lt;/span&gt;file&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;586484&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive&lt;span style="color:#f92672"&gt;(&lt;/span&gt;file&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;484544&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;实际上lruvec不止一个，cgroup、NUMA node都有自己的lruvec，同时global也有自己的lruvec&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d25a7970acd0.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;drop cache
 &lt;div id="drop-cache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#drop-cache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;Dropcache会记录哪些页面是缓存文件系统数据的页面，并在页面被强制回收时把数据写回磁盘，以便下次访问时可以再次缓存。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;默认值：&lt;code&gt;vm.drop_caches = 0&lt;/code&gt;。默认情况下，Linux内核不会自动清除缓存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/proc/sys/vm/drop_caches&lt;/code&gt;的值设置为1：内核会清除未使用的页缓存pagecache。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/proc/sys/vm/drop_caches&lt;/code&gt;的值设置为2：内核会释放dentry和inode所使用的内存，dentry和inode是文件系统元数据结构，用于存储文件和目录的信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/proc/sys/vm/drop_caches&lt;/code&gt;的值设置为3：效果相当于1+2，释放所有未使用的缓存&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当内核决定回收某些缓存时，它会检查缓存中的数据与硬盘上的数据是否一致。如果数据不一致，内核需要将数据写回磁盘，然后才能回收该缓存。这个过程可能导致IO飙高。在进行Drop Cache操作时，建议不要有任何重要的I/O操作，因为这可能会影响系统性能。&lt;/p&gt;
&lt;p&gt;操作命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo 3 &amp;gt; /proc/sys/vm/drop_caches #刷cache缓存
echo 0 &amp;gt; /proc/sys/vm/drop_caches #恢复默认值
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class="relative group"&gt;内存的监控
 &lt;div id="内存的监控" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e7%9a%84%e7%9b%91%e6%8e%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;如果不了解内存的基本知识其实很难看懂内存监控信息，在有了以上内存基础的情况下，我们来一个个过内存相关监控命令、工具的使用。&lt;/p&gt;

&lt;h3 class="relative group"&gt;/proc 目录有些什么？
 &lt;div id="proc-目录有些什么" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#proc-%e7%9b%ae%e5%bd%95%e6%9c%89%e4%ba%9b%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;/proc 主要是进程 (process)信息和系统信息&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/539736f743ba.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;其中system information部分，有些是linux提供的一些系统状态的接口，可以查看整个操作系统层面的监控信息，比如slabinfo,swaps,zoneinfo,buddyinfo&lt;/p&gt;
&lt;p&gt;另一部分process是每个进程运行数据和状态信息，cd到对应进程目录下，可以看到对应进程的持有的fd和进程内存信息等&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e5f7e542f245.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/de0fd3de265d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;进程下面还有线程，线程的信息目录：/proc/[pid]/task/[tid]/，其下内容跟进程目录下面差不多。&lt;/p&gt;
&lt;p&gt;更多的proc信息参考&lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html" target="_blank" rel="noreferrer"&gt;proc(5) — Linux manual page&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;/proc/meminfo
 &lt;div id="procmeminfo" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#procmeminfo" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;/proc/meminfo是了解当前Linux系统内存使用状况的主要接口，最常用的&lt;code&gt;free&lt;/code&gt;,&lt;code&gt;vmstat&lt;/code&gt;,&lt;code&gt;ps&lt;/code&gt;等命令就是通过它获取数据。/proc/meminfo的信息要更加全面，下面只列出一些常见的信息，详细含义可参考&lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo" target="_blank" rel="noreferrer"&gt;红帽文档&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#一般的内存信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep &lt;span style="color:#e6db74"&gt;&amp;#34;Mem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MemTotal: &lt;span style="color:#ae81ff"&gt;994328&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#总内存大小（减去一些保留的和内核的）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MemFree: &lt;span style="color:#ae81ff"&gt;66428&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#完全没有用到的物理内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MemAvailable: &lt;span style="color:#ae81ff"&gt;207192&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#在不使用交换空间的情况下，启动一个新的应用最大可用内存的大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#IO缓冲区&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -e &lt;span style="color:#e6db74"&gt;&amp;#34;Buffers&amp;#34;&lt;/span&gt; -we &lt;span style="color:#e6db74"&gt;&amp;#34;Cached&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Buffers: &lt;span style="color:#ae81ff"&gt;12820&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#raw disk block使用的IO缓冲区，不会超过20MB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cached: &lt;span style="color:#ae81ff"&gt;254592&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#磁盘使用的page cache size（包含tmpfs和shmem不包含SwapCached）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#swap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep &lt;span style="color:#e6db74"&gt;&amp;#34;Swap&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SwapCached: &lt;span style="color:#ae81ff"&gt;13936&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#swap cache中包含的是被确定要swapping换页，但是尚未写入物理交换区的匿名内存页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SwapTotal: &lt;span style="color:#ae81ff"&gt;945416&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#swap空间总大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SwapFree: &lt;span style="color:#ae81ff"&gt;851064&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#剩余的swap的大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#lru活动与非活动页数（一眼懂）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -e &lt;span style="color:#e6db74"&gt;&amp;#34;Active&amp;#34;&lt;/span&gt; -e &lt;span style="color:#e6db74"&gt;&amp;#34;Inactive&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active: &lt;span style="color:#ae81ff"&gt;194308&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive: &lt;span style="color:#ae81ff"&gt;553172&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active&lt;span style="color:#f92672"&gt;(&lt;/span&gt;anon&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;59024&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive&lt;span style="color:#f92672"&gt;(&lt;/span&gt;anon&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;437264&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Active&lt;span style="color:#f92672"&gt;(&lt;/span&gt;file&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;135284&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Inactive&lt;span style="color:#f92672"&gt;(&lt;/span&gt;file&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;115908&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#脏页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -e &lt;span style="color:#e6db74"&gt;&amp;#34;Dirty&amp;#34;&lt;/span&gt; -e &lt;span style="color:#e6db74"&gt;&amp;#34;Writeback&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dirty: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#还未写入的脏页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Writeback: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#正在写入的脏页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WritebackTmp: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#？temporary buffer for writebacks used by the FUSE module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#map信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -e &lt;span style="color:#e6db74"&gt;&amp;#34;AnonPages&amp;#34;&lt;/span&gt; -e &lt;span style="color:#e6db74"&gt;&amp;#34;Map&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AnonPages: &lt;span style="color:#ae81ff"&gt;95296&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#map的匿名页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mapped: &lt;span style="color:#ae81ff"&gt;153192&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#map的文件页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DirectMap4k: &lt;span style="color:#ae81ff"&gt;113336&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#map的4k内核页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DirectMap2M: &lt;span style="color:#ae81ff"&gt;1900544&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#map的2M内核页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DirectMap1G: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#map的1G内核页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#共享内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep &lt;span style="color:#e6db74"&gt;&amp;#34;Shmem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shmem: &lt;span style="color:#ae81ff"&gt;28920&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#shmem和tmpfs的总内存大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ShmemHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#shmem和tmpfs的总大页内存大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ShmemPmdMapped: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#Shared memory mapped into userspace with huge pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#内核内存（注意slab就是内核的）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -ie &lt;span style="color:#e6db74"&gt;&amp;#34;reclaim&amp;#34;&lt;/span&gt; -e &lt;span style="color:#e6db74"&gt;&amp;#34;slab&amp;#34;&lt;/span&gt; -e &lt;span style="color:#e6db74"&gt;&amp;#34;kernel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KReclaimable: &lt;span style="color:#ae81ff"&gt;35008&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#分配给内核的Reclaimable内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Slab: &lt;span style="color:#ae81ff"&gt;88752&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#slab cache&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SReclaimable: &lt;span style="color:#ae81ff"&gt;35008&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#slab cache中Reclaimable内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SUnreclaim: &lt;span style="color:#ae81ff"&gt;53744&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#slab cache中不能reclaim的内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KernelStack: &lt;span style="color:#ae81ff"&gt;5988&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#所有任务使用的kernel stack内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#分配的可用内存（与MemAvailable含义不同）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## CommitLimit=[(&amp;#34;total RAM pages&amp;#34; - &amp;#34;total huge TLB pages&amp;#34;) * overcommit_ratio]/100 + &amp;#34;total swap pages&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 简而言之，设置了MemAvailable的水位然后加上了swap就等于allocatable内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -ie &lt;span style="color:#e6db74"&gt;&amp;#34;commit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CommitLimit: &lt;span style="color:#ae81ff"&gt;1442580&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#allocatable内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Committed_AS: &lt;span style="color:#ae81ff"&gt;3035924&lt;/span&gt; kB		&lt;span style="color:#75715e"&gt;#预估当前最坏场景下，需要分配的内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#虚拟内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -e &lt;span style="color:#e6db74"&gt;&amp;#34;Vmalloc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmallocTotal: &lt;span style="color:#ae81ff"&gt;34359738367&lt;/span&gt; kB	&lt;span style="color:#75715e"&gt;#已分配的虚拟内存总大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmallocUsed: &lt;span style="color:#ae81ff"&gt;34780&lt;/span&gt; kB			&lt;span style="color:#75715e"&gt;#已使用的虚拟内存总大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmallocChunk: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB			&lt;span style="color:#75715e"&gt;#最大的连续虚拟内存块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#page table占用的内存（一眼懂）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep PageTables
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PageTables: &lt;span style="color:#ae81ff"&gt;4120&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#大页内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/meminfo | grep -i hugepage
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AnonHugePages: &lt;span style="color:#ae81ff"&gt;32768&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ShmemHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FileHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HugePages_Total: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HugePages_Free: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HugePages_Rsvd: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HugePages_Surp: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hugepagesize: &lt;span style="color:#ae81ff"&gt;2048&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;/proc/buddyinfo
 &lt;div id="procbuddyinfo" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#procbuddyinfo" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;buddyinfo由于信息简洁易懂，是最为常用的判断内存碎片问题的方式。详见 “内存分配-buddy章节”&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/buddyinfo 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone DMA32 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;272&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal &lt;span style="color:#ae81ff"&gt;317681&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38869&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31620&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19250&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8931&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2579&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;815&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;182&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;/proc/pagetypeinfo
 &lt;div id="procpagetypeinfo" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#procpagetypeinfo" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pagetypinfo首先提供有关页块大小的信息。它提供与buddyinfo相同类型的信息，但按类型进行细分并详细说明每种类型的页的数量。&lt;/p&gt;
&lt;p&gt;在理解pagetypeinfo前，需要先了解下&lt;a href="https://lwn.net/Articles/368869/" target="_blank" rel="noreferrer"&gt;memory compaction&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;假如一个zone中的内存如下：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/97866485c91f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;白色代表可用内存，红色代表已使用内存。以上内存的碎片化已经比较严重了，如果此时有请求2阶以上的内存，是无法分配的。此时该memory compaction发生作用了，压缩算法会在原有的zone上标记movable pages和Free pages链表。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/706746415abf.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;movable扫描器从底部到顶部扫描，free扫描器从顶部到底部扫描，movable和free扫描器最终会在中间的某点相遇。然后通过&lt;a href="https://lwn.net/Articles/157066/" target="_blank" rel="noreferrer"&gt;页迁移&lt;/a&gt;将已使用页转移到zone的顶端。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8b308995434f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;page compation两种触发方式&lt;/em&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当分配page的时候，在LOW水位出现分配失败的时候，会尝试慢速内存分配，过程中就会出现page compaction&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;echo x &amp;gt; /proc/sys/vm/compact_memory&lt;/code&gt;来启动page compaction的动作，启动后内核线程&lt;code&gt;kcompactd&lt;/code&gt;就会启动来进行页面整理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为⻚⾯中数据被迁移到新位置，所以不会有采取的内存回收导致的那么⼤的性能问题，⽽且因为⽬标更明确，得到的连续⻚⾯的成本也更低。 另外ANON⻚⾯回收是需要SWAP的，⽽这⾥不需要。&lt;/p&gt;
&lt;p&gt;此时再来看下/proc/pagetypeinfo的信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat /proc/pagetypeinfo 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Page block order: &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pages per block: &lt;span style="color:#ae81ff"&gt;512&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...（DMA忽略）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type Unmovable &lt;span style="color:#ae81ff"&gt;870&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;530&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;391&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;157&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;103&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type Movable &lt;span style="color:#ae81ff"&gt;5886&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9235&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5728&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4072&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1561&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;324&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;115&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13018&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type Reclaimable &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type HighAtomic &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type CMA &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Node 0, zone Normal, type Isolate &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不同的page被分类，称为pageblock。每个pageblock根据其类型不同分成⼏个列表，分配内存的时候，根据申请⻚⾯类型的不同，向相应的列表中申请⻚⾯，⽽释放的时候也会根据其所属pageblock回到相应列表。不同的pageblock：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unmovable：无法压缩的page&lt;/li&gt;
&lt;li&gt;Movable：可压缩的page&lt;/li&gt;
&lt;li&gt;Reclaimable：可以回收的page&lt;/li&gt;
&lt;li&gt;HighAtomic：为了缓解碎片问题增加的pageblock。高阶并且具备同等级别的才能从该pageblock中申请page&lt;/li&gt;
&lt;li&gt;CMA：CMA 全称是 Contiguous Memory Allocator（连续内存分配器）&lt;/li&gt;
&lt;li&gt;Isolate：⻚⾯不会被分配，⽤来帮助isolate⻚⾯。isolate⻚⾯的时候会将⻚块先设置为isolate防⽌其被释放&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CMA看上去又是一个大块知识，可以简单理解为buddy系统的补充：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a9cd9dcbfe80.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（内存之旅——如何提升CMA利用率？ &lt;a href="https://ost.51cto.com/posts/10815" target="_blank" rel="noreferrer"&gt;https://ost.51cto.com/posts/10815&lt;/a&gt;）&lt;/p&gt;

&lt;h3 class="relative group"&gt;smaps &amp;amp; maps &amp;amp; pmap
 &lt;div id="smaps--maps--pmap" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#smaps--maps--pmap" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;VSS/RSS/PSS/USS&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;查看一个进程占用的内存，常有VSS/RSS/PSS/USS四种形式，主要是内存计算的口径不同&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/21b9b29f53a3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://cloud.tencent.com/developer/article/1683708）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;VSS（Virtual Set Size）只是一个虚拟空间大小，对内存实际占用量意义不大。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RSS（Resident Set Size）是对于计算一个进程总的内存占用量，包括共享库占用的共享内存大小，比如私有内存大小N，共享内存大小M，则RSS=N+M。肯能会有一点误解，因为像libc这种大部头库文件，共享者很多，都算在一个进程头上不科学。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PSS （Proportional Set Size）是单个进程运行时实际占用的物理内存大小，包含比例分配共享库占用的内存，一个共享库有 N 个进程使用，那么该库比例分配给 PSS 的大小为 1/N。PSS计算进程内存更准确，除了自己独占的内存，再加上分到的共享部分。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;USS （Unique Set Size）是进程独自占用的物理内存大小，不包含共享内存&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;/proc/[pid]/maps&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;/proc/[pid]/maps可查看&lt;strong&gt;进程&lt;/strong&gt;的&lt;strong&gt;虚拟内存&lt;/strong&gt;的&lt;strong&gt;用户空间&lt;/strong&gt;内存映射&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl 2345&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat maps 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;起始地址-结束地址 权限 偏移地址 主次设备号 inode编号												 文件名
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00400000-00bae000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; fd:00 &lt;span style="color:#ae81ff"&gt;1093852&lt;/span&gt; /pg/pg15.3/bin/postgres ---代码段
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00dad000-00dc3000 rw-p 007ad000 fd:00 &lt;span style="color:#ae81ff"&gt;1093852&lt;/span&gt; /pg/pg15.3/bin/postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00dc3000-00df5000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00f1e000-00f60000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;heap&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ---heap区
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;33a6000000-33a6022000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; fd:00 &lt;span style="color:#ae81ff"&gt;1976006&lt;/span&gt; /lib64/ld-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe2ae09000-7fbe2ae0a000 rw-p 0000c000 fd:00 &lt;span style="color:#ae81ff"&gt;1975966&lt;/span&gt; /lib64/libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe2ae1b000-7fbe33ca7000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;12556&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe33ca7000-7fbe39b38000 r--p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; fd:00 &lt;span style="color:#ae81ff"&gt;1181300&lt;/span&gt; /usr/lib/locale/locale-archive
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe39b38000-7fbe39b3d000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe39b46000-7fbe39b4d000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:10 &lt;span style="color:#ae81ff"&gt;12559&lt;/span&gt; /dev/shm/PostgreSQL.3661351388
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe39b4d000-7fbe39b4e000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;32769&lt;/span&gt; /SYSV0010c0b6 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe39b4e000-7fbe39b4f000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fffe3933000-7fffe3948000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;stack&lt;span style="color:#f92672"&gt;]&lt;/span&gt; --stack区 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fffe397d000-7fffe397e000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;vdso&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffffffffff600000-ffffffffff601000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;vsyscall&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(1)起始地址-结束地址：本段在虚拟内存中的地址范围
(2)权限：本段的权限; r-读，w-写，x-执行， p-私有
(3)偏移地址：即本段映射地址在文件中的偏移
(4)主次设备号：所映射的文件所属设备的设备号，对应vm_file-&amp;gt;f_dentry-&amp;gt;d_inode-&amp;gt;i_sb-&amp;gt;s_dev。&lt;strong&gt;匿名映射为0。其中fd为主设备号，00为次设备号。&lt;/strong&gt;
(5)inode号：对应vm_file-&amp;gt;f_dentry-&amp;gt;d_inode-&amp;gt;i_ino，&lt;strong&gt;与ls –i显示的内容相符，匿名映射为0&lt;/strong&gt;。
(6)映射的文件名：对有名映射而言，是映射的文件名，对匿名映射来说，是此段内存在进程中的作用&lt;/p&gt;
&lt;p&gt;以下是文心的分析：（真给它分析出来了，这是一个postgres主进程）&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/639e6e130d4f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;/proc/[pid]/smaps&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;/proc/[pid]/smaps 文件是基于 /proc/[pid]/maps 的扩展，比同一目录下的maps文件更为详细。每一个VMA都有如下的一系列数据：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl 2345&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat smaps 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00400000-00bae000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; fd:00 &lt;span style="color:#ae81ff"&gt;1093852&lt;/span&gt; /pg/pg15.3/bin/postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;7864&lt;/span&gt; kB --VSS内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;408&lt;/span&gt; kB		--RSS内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;140&lt;/span&gt; kB		--PSS内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Clean: &lt;span style="color:#ae81ff"&gt;404&lt;/span&gt; kB		--共享的、干净的内存大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Dirty: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		--共享的、已脏的（即已修改）的内存大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Clean: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB		--私有的、干净的内存大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Dirty: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		--私有的、已脏的内存大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Referenced: &lt;span style="color:#ae81ff"&gt;408&lt;/span&gt; kB		--当前页面被标记为已引用或者包含匿名映射
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Anonymous: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		--匿名页
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AnonHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		--匿名大页
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB		--已交欢出的内存大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KernelPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB		--内核页面大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MMUPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB		--pagetable页面大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fffe3933000-7fffe3948000 rw-p &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:00 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;stack&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;现在知道，maps是进程的内存映射信息，smaps还包含每段映射的内存大小（VSS,RSS,PSS）。&lt;/p&gt;
&lt;p&gt;可通过查看进程smaps的PSS、RSS等数据，计算出进程的内存用量，注意单位是kb&lt;/p&gt;
&lt;p&gt;&lt;em&gt;所有进程的物理总内存使用量&lt;/em&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep Pss /proc/&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;*/smaps | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{total+=$2}; END {printf &amp;#34;%d kB\n&amp;#34;, total }&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;某进程PSS内存&lt;/em&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/90875/smaps |grep Pss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;某进程的RSS内存&lt;/em&gt; ：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/68729/smaps |grep Rss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;某进程私有内存&lt;/em&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/90875/smaps|sed &lt;span style="color:#e6db74"&gt;&amp;#39;/zero/,/VmFlags/d&amp;#39;&lt;/span&gt; |grep Private |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;pmap&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;pmap命令解析的是/proc/[pid]/maps和/proc/[pid]/smaps文件。参数不多，-x表示展示更多信息&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# pmap -x 2345&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2345: /pg/pg15.3/bin/postgres -D /pg/1503data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Address Kbytes RSS Dirty Mode Mapping
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000400000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7864&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;212&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000dad000 &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; rw--- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000dc3000 &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000f1e000 &lt;span style="color:#ae81ff"&gt;264&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000033a6000000 &lt;span style="color:#ae81ff"&gt;136&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;108&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- ld-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe2ae09000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw--- libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe2ae1b000 &lt;span style="color:#ae81ff"&gt;145968&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4396&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4396&lt;/span&gt; rw-s- zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe33ca7000 &lt;span style="color:#ae81ff"&gt;96836&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r---- locale-archive
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b38000 &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b46000 &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; rw-s- PostgreSQL.3661351388
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b4d000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw-s- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x8001 &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b4e000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe3933000 &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; stack &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe397d000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffffffffff600000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---------------- ------ ------ ------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total kB &lt;span style="color:#ae81ff"&gt;268896&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5532&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4540&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pmap输出格式跟/proc/[pid]/maps差不多，每个vma地址一行，但是比maps多了VSS和RSS，这样就可以直接看进程虚拟内存的每个区域所使用的大小，帮助快速判断内存较多的区域在哪。&lt;/p&gt;
&lt;p&gt;如果地址空间中[heap]太大，那有可能是堆内存产生了泄漏；再比如说，如果进程地址空间包含太多的 vma（可以把 maps 中的每一行理解为一个 vma），那很可能是应用程序调用了很多 mmap 而没有 munmap；再比如持续观察地址空间的变化，如果发现某些项在持续增长，那很可能是那里存在问题&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;分析示例&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;从主机的TOP的内存查看某pg backend进程内存看上去比较高，此时需要进一步分析map信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;68729&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5579004&lt;/span&gt; 5.116g 5.114g R 97.4 1.4 128:27.94 postgres: lzl: lzldb lzl 30.78.14.174&lt;span style="color:#f92672"&gt;(&lt;/span&gt;58067&lt;span style="color:#f92672"&gt;)&lt;/span&gt; DELETE &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看这个进程Rss、Pss、Uss&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/68729/smaps |grep Rss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5422.67 ---5.4G Rss
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/68729/smaps |grep Pss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;467.957	 ---467mb Pss
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/68729/smaps|sed &lt;span style="color:#e6db74"&gt;&amp;#39;/zero/,/VmFlags/d&amp;#39;&lt;/span&gt; |grep Private |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;179.605 ---179mb Uss&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Rss-Uss=5.3G的共享内存，从Pss-Uss=290mb的proportion共享内存，大致能看出这个backend只是这个共享内存proportion的一小部分&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pmap -x &lt;span style="color:#ae81ff"&gt;68729&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;68729: postgres: pdmp: pdmpdata pdmp 30.78.14.174&lt;span style="color:#f92672"&gt;(&lt;/span&gt;46252&lt;span style="color:#f92672"&gt;)&lt;/span&gt; DELETE 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Address Kbytes RSS Dirty Mode Mapping
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000400000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6084&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2444&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000bf0000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; r---- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000bf1000 &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; rw--- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b7f65bfa000 &lt;span style="color:#ae81ff"&gt;5441216&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5365444&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5365444&lt;/span&gt; rw-s- zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt; --这部分占用最多
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80b1daa000 &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80b1db6000 &lt;span style="color:#ae81ff"&gt;2044&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ----- libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80b1fb5000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; r---- libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80b1fb6000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; rw--- libnss_files-2.17.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80b1fb7000 &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00002b80ba001000 &lt;span style="color:#ae81ff"&gt;516&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;516&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;516&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe16f7000 &lt;span style="color:#ae81ff"&gt;132&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; stack &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe175b000 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffffffffff600000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;继续深入到smap分析，可以直接定位到zero (deleted)这部分&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat smaps 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00400000-009f1000 r-xp &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; fd:06 &lt;span style="color:#ae81ff"&gt;58726481&lt;/span&gt; /paic/postgres/base/9.6.6/bin/postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b7f65bfa000-2b80b1daa000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;72254&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;5441216&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;5365444&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;264618&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Clean: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Dirty: &lt;span style="color:#ae81ff"&gt;5365444&lt;/span&gt; kB --共享的脏数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Clean: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Dirty: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Referenced: &lt;span style="color:#ae81ff"&gt;5364764&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Anonymous: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AnonHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KernelPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MMUPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locked: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmFlags: rd wr sh mr mw me ms sd &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;从以上分析可以得出：这是个pg的私有进程，变动了大量数据还没有刷脏，自己私有内存不多，大部分都是共享内存中占用的。这很有可能是一个pg中的事务变动了很多数据暂时还没提交。&lt;/p&gt;
&lt;p&gt;另外，/dev/zero (deleted)在&lt;a href="https://www.man7.org/linux/man-pages/man5/proc.5.html" target="_blank" rel="noreferrer"&gt;proc(5) — Linux manual page&lt;/a&gt;有解释:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Although these entries are present for memory regions that were mapped with the MAP_FILE flag, the way anonymous shared memory (regions created with the MAP_ANON | MAP_SHARED flags) is implemented in Linux means that such regions also appear on this directory. Here is an example where the target file is the deleted /dev/zero one:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; lrw-------. 1 root root 64 Apr 16 21:33
 7fc075d2f000-7fc075e6f000 -&amp;gt; /dev/zero (deleted)
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;&lt;p&gt;“非专业翻译”：匿名页和共享页由 /dev/zero (deleted)表示&lt;/p&gt;

&lt;h3 class="relative group"&gt;/proc/[pid]/status
 &lt;div id="procpidstatus" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#procpidstatus" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;status可查看进程的状态信息，包含一部分内存信息。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl 2345&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat status &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Name: postgres			---运行这个线程的命令
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State: S &lt;span style="color:#f92672"&gt;(&lt;/span&gt;sleeping&lt;span style="color:#f92672"&gt;)&lt;/span&gt;	---进程状态
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Tgid: 2345					---Thread group ID &lt;span style="color:#f92672"&gt;(&lt;/span&gt;i.e., Process ID&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pid: 2345					---Thread ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PPid: 1	 					---PID of parent process.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmPeak: &lt;span style="color:#ae81ff"&gt;268964&lt;/span&gt; kB		---虚拟内存峰值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmSize: &lt;span style="color:#ae81ff"&gt;268896&lt;/span&gt; kB		---虚拟内存当前值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmLck: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmHWM: &lt;span style="color:#ae81ff"&gt;13400&lt;/span&gt; kB		---RSS的峰值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmRSS: &lt;span style="color:#ae81ff"&gt;5532&lt;/span&gt; kB		---RSS的当前值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmData: &lt;span style="color:#ae81ff"&gt;528&lt;/span&gt; kB		---数据段
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmStk: &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; kB		---stack段
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmExe: &lt;span style="color:#ae81ff"&gt;7864&lt;/span&gt; kB		---text段
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmLib: &lt;span style="color:#ae81ff"&gt;3100&lt;/span&gt; kB		---共享库代码段
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmPTE: &lt;span style="color:#ae81ff"&gt;136&lt;/span&gt; kB		---Page table entries
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmSwap: &lt;span style="color:#ae81ff"&gt;308&lt;/span&gt; kB		---swap的大小
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Threads: 1			---该进程的线程数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;....&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;status相对map，没有映射信息，内存数据更概况一些，也可以更直观的看到虚拟内存的每个段所占用的大小&lt;/p&gt;
&lt;p&gt;&lt;em&gt;查看SWAP用量最多的进程&lt;/em&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; file in /proc/*/status ; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; awk &lt;span style="color:#e6db74"&gt;&amp;#39;/VmSwap|Name|^Pid/{printf $2 &amp;#34; &amp;#34; $3}END{ print &amp;#34;&amp;#34;}&amp;#39;&lt;/span&gt; $file; &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt; | sort -k &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; -n -r | head&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;cgroup memory
 &lt;div id="cgroup-memory" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cgroup-memory" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" target="_blank" rel="noreferrer"&gt;cgroup的memory控制&lt;/a&gt;现在已经很常见。一些主机参数需要在cgroup中设置。内存设置、监控信息均在/sys/fs/cgroup/memory/下面&lt;/p&gt;
&lt;p&gt;cginfo查看CGROUP内存分配和使用情况 ： /opt/cgtools/cginfo -t perf -s mem&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cginfo -t perf -s mem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;====================&lt;/span&gt; Cgroup Performance: memory &lt;span style="color:#f92672"&gt;====================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DB_TYPE INSTANCE_NAME MEM_OOM MEM_FILE_GB MEM_MAP_GB MEM_USED_GB MEM_ALLO_GB ALLO_RATE MEM_GLOB_GB GLOB_RATE 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------- ------------- ------- ----------- ---------- ----------- ----------- --------- ----------- --------- 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres LZLDB &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 154.3 0.0 4.2 160.0 2.6% &lt;span style="color:#ae81ff"&gt;375&lt;/span&gt; 1.1% &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看比较详细的CGROUP内存使用状态: /sys/fs/cgroup/memory/[group]/memory.stat&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat memory.stat 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_cache &lt;span style="color:#ae81ff"&gt;167791534080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_rss &lt;span style="color:#ae81ff"&gt;4006932480&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_rss_huge &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_mapped_file &lt;span style="color:#ae81ff"&gt;11747328&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_swap &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_pgpgin &lt;span style="color:#ae81ff"&gt;792754417976&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_pgpgout &lt;span style="color:#ae81ff"&gt;792712474991&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_pgfault &lt;span style="color:#ae81ff"&gt;477971874868&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_pgmajfault &lt;span style="color:#ae81ff"&gt;97318&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_inactive_anon &lt;span style="color:#ae81ff"&gt;1610874880&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_active_anon &lt;span style="color:#ae81ff"&gt;2408255488&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_inactive_file &lt;span style="color:#ae81ff"&gt;73446166528&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_active_file &lt;span style="color:#ae81ff"&gt;94332768256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_unevictable &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;smem
 &lt;div id="smem" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#smem" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://linux.die.net/man/8/smem" target="_blank" rel="noreferrer"&gt;smem&lt;/a&gt;是一款强大的展示内存使用情况的工具，读取/proc下面的smaps、meminfo等信息然后汇总输出。smem可以输出总体和具体map的内存情况，非常直观而且可以从不同的维度去分析，总体是一款分析内存使用非常好用的工具。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://selenic.com/repo/smem" target="_blank" rel="noreferrer"&gt;repo&lt;/a&gt;可直接下载，基本上解压即可使用。更多用法可参考&lt;a href="https://www.selenic.com/smem/" target="_blank" rel="noreferrer"&gt;smem memory reporting tool&lt;/a&gt;，以下只简单示例：&lt;/p&gt;
&lt;p&gt;查看系统内存使用 &lt;code&gt;-w&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# smem -w -k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Area Used Cache Noncache 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;firmware/hardware &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel image &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel dynamic memory 183.9M 84.0M 99.9M 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userspace memory 112.3M 62.2M 50.1M 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;free memory 700.3M 700.3M &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看每个用户的内存消耗 &lt;code&gt;-u&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# smem -s pss -urk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User Count Swap USS PSS RSS 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oracle &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; 85.2M 30.8M 95.7M 383.0M 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;93&lt;/span&gt; 112.4M 38.5M 42.3M 86.2M 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; 5.9M 1.6M 2.5M 5.9M 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 169.7M 1.7M 1.7M 2.0M &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看某个用户的内存消耗&lt;code&gt;-U&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# smem -U pg -k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PID User Command Swap USS PSS RSS 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2345&lt;/span&gt; pg /pg/pg15.3/bin/postgres -D 364.0K 124.0K 134.0K 228.0K 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2352&lt;/span&gt; pg postgres: logical replicati 636.0K 144.0K 161.0K 196.0K 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;过滤某个进程 &lt;code&gt;-P&lt;/code&gt;（PROCESSFILTER，不是pid）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@lzl ~]# smem -P postgres -p
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PID User Command Swap USS PSS RSS 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2346 pg /pg/pg16.0/bin/postgres -D 0.01% 0.01% 0.01% 0.01% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2350 pg postgres: walwriter 0.01% 0.01% 0.01% 0.01% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看进程的mapping和内存占用情况 &lt;code&gt;-m&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# smem -P postgres -mpr -s pss&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Map PIDs AVGPSS PSS 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;anonymous&amp;gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; 0.02% 0.24% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;heap&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 0.07% 0.20% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/lib64/libpython2.6.so.1.0 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 0.11% 0.11% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/pg/pg15.3/bin/postgres &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 0.01% 0.06% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/pg/pg16.0/bin/postgres &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 0.01% 0.06% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/dev/zero &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; 0.00% 0.03% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;stack&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; 0.00% 0.02% 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;smem看进程内存的USS\PSS\RSS很直观，不过有个问题，smem不能过滤pid，只能通过用户名或PROCESSFILTER去过滤，对于一个主机部署多个数据库实例时，过滤父PID或子PID，不是很友好。&lt;/p&gt;

&lt;h3 class="relative group"&gt;top
 &lt;div id="top" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#top" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man1/top.1.html" target="_blank" rel="noreferrer"&gt;top&lt;/a&gt;可实时的展示系统运行状态。top玩法也可以非常花哨，直接top运行同样可以展示非常多的信息。&lt;/p&gt;
&lt;p&gt;使用top中的排序：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command sorted-field supported
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;M %MEM Yes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;N PID Yes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;P %CPU Yes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;T TIME+ Yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以用%MEM来排序内存占用较多的进程，%MEM表示RES的内存百分比&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;top - 23:38:01 up &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; days, 22:32, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; users, load average: 1.12, 1.42, 1.09
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Tasks: &lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; total, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; running, &lt;span style="color:#ae81ff"&gt;183&lt;/span&gt; sleeping, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; stopped, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; zombie
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cpu&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 1020348k total, 325848k used, 694500k free, 1352k buffers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 4128760k total, 635872k used, 3492888k free, 150288k cached
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;18537&lt;/span&gt; oracle &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 636m 24m 21m S 0.0 2.4 0:05.41 oracle 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;18533&lt;/span&gt; oracle &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 638m 24m 21m S 0.0 2.4 0:02.01 oracle 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;... 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;18509&lt;/span&gt; oracle &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 634m &lt;span style="color:#ae81ff"&gt;4384&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4036&lt;/span&gt; S 0.0 0.4 0:01.93 oracle 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2639&lt;/span&gt; root &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 729m &lt;span style="color:#ae81ff"&gt;4052&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1444&lt;/span&gt; S 0.0 0.4 8:45.32 nautilus &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;内存相关的解读：&lt;/p&gt;
&lt;p&gt;第四行：
内存使用信息：物理内存量、已用内存量、空闲内存量、缓冲内存量
第五行：
交换分区信息：可用交换区总量、已用交换区总量、空闲交换区总量、内核用于缓存的数量&lt;/p&gt;
&lt;p&gt;第六行（内存相关）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VIRT：VSS&lt;/li&gt;
&lt;li&gt;RES：RSS（likely），anything occupying physical memory&lt;/li&gt;
&lt;li&gt;SHR：Shared Memory Size。It will include shared anonymous pages and shared file-backed pages&lt;/li&gt;
&lt;li&gt;%MEM： RSS百分比，A task&amp;rsquo;s currently resident share of available physical memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，查看内存的时候不要忘了看一眼进程的状态&lt;/p&gt;
&lt;p&gt;S（示例第八列）Process Status：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;D = uninterruptible sleep。不可中断的睡眠状态。表示该进程正在等待某个外部事件完成，如磁盘I/O操作或网络请求。通常情况下，D进程不能被直接终止。&lt;/li&gt;
&lt;li&gt;I = idle&lt;/li&gt;
&lt;li&gt;R = running&lt;/li&gt;
&lt;li&gt;S = sleeping&lt;/li&gt;
&lt;li&gt;T = stopped by job control signal&lt;/li&gt;
&lt;li&gt;t = stopped by debugger during trace&lt;/li&gt;
&lt;li&gt;Z = zombie&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;top命令可以看到主机的内存汇总信息，进程使用内存信息有RSS,SHR，粗略算一下RES-SHR=USS也可以计算私有内存的占用大小，另外还可以看到进程状态，所以top -p查看某进程的内存基本信息还是很好用的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;free
 &lt;div id="free" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#free" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man1/free.1.html" target="_blank" rel="noreferrer"&gt;free&lt;/a&gt;展示主机的swap、内存的总量和剩余量，信息都是解析自/proc/meminfo&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user@ubuntu:~$ free
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total used free shared buff/cache available
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 8029356 794336 6297928 183384 937092 6816804
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 0 0 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;total ：Total usable memory (MemTotal and SwapTotal in /proc/meminfo). This includes the physical and swap memory minus a few reserved bits and kernel binary code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;used ： Used or unavailable memory (calculated as total - available)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;free：Unused memory (MemFree and SwapFree in /proc/meminfo) shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;buffers：Memory used by kernel buffers (Buffers in /proc/meminfo)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cache：Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)。不仅有pagecache，还有SReclaimable的slab！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;buff/cache：Sum of buffers and cache&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;available：cache包含pagecache和SReclaimable，free包含mem free和swap free；而available包含pagecache和即将被reclaim的内存；表示可用内存，但它们的计算方式不同，在实际应用中，由于缓存的存在，available通常会比free大&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Page Cache：
Page cache 主要用来作为文件系统上的文件数据的缓存来用，尤其是针对当进程对文件有 read/write 操作的时候。&lt;/p&gt;
&lt;p&gt;Buffer Cache：
Buffer cache 则主要是设计用来在系统对块设备进行读写的时候，对块进行数据缓存的系统来使用&lt;/p&gt;

&lt;h3 class="relative group"&gt;ps aux
 &lt;div id="ps-aux" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ps-aux" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ps最大的好处就是从进程的角度分析进程状态（包括内存），COMMAND带[ ]标志的进程为kernel进程。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg@lzl ~]$ ps aux|head -1;ps aux|grep postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2345 0.0 0.0 268896 236 ? Ss Jan01 0:03 /pg/pg15.3/bin/postgres -D /pg/1503data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2353 0.0 0.0 269040 196 ? Ss Jan01 0:00 postgres: checkpointer 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2354 0.0 0.0 269032 160 ? Ss Jan01 0:02 postgres: background writer 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2356 0.0 0.0 269032 116 ? Ss Jan01 0:01 postgres: walwriter 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2357 0.0 0.0 270508 824 ? Ss Jan01 0:02 postgres: autovacuum launcher 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 2358 0.0 0.0 270492 620 ? Ss Jan01 0:00 postgres: logical replication launcher 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg 29818 0.0 0.0 103372 868 pts/0 S+ 09:16 0:00 grep postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;VSZ,RSS单位是kb。内存信息比较少，VSZ没什么价值，RSS可以参考一下，没有PSS，USS这类信息，能分析的内容不多&lt;/p&gt;

&lt;h3 class="relative group"&gt;ipcs
 &lt;div id="ipcs" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ipcs" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ipcs -m&lt;/code&gt; 是一个用于查询 IPC（进程间通信）共享内存资源的命令。分析共享内存的时候比较有用。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ipcs -m
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------ Shared Memory Segments --------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;key shmid owner perms bytes nattch status 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x0010c0b6 &lt;span style="color:#ae81ff"&gt;32769&lt;/span&gt; pg &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;共享内存的 key 值&lt;/li&gt;
&lt;li&gt;共享内存的编号 (shmid)&lt;/li&gt;
&lt;li&gt;创建该共享内存的用户&lt;/li&gt;
&lt;li&gt;权限（perms）&lt;/li&gt;
&lt;li&gt;创建的大小（bytes）&lt;/li&gt;
&lt;li&gt;连接到该共享内存的进程数（nattach）&lt;/li&gt;
&lt;li&gt;共享内存的状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时连接一个会话到PostgreSQL，会多一个backend进程&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------ Shared Memory Segments --------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;key shmid owner perms bytes nattch status 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0x0010c0b6 &lt;span style="color:#ae81ff"&gt;32769&lt;/span&gt; pg &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;nattch+1，说明私有的backend进程也分享了一部分PG共享出来的内存。此时理解下面这个图也更深刻&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/75c502689001.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（http://gauss.ececs.uc.edu/Courses/c4029/code/memory/virtual.pdf）&lt;/p&gt;

&lt;h3 class="relative group"&gt;vmstat
 &lt;div id="vmstat" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vmstat" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man8/vmstat.8.html" target="_blank" rel="noreferrer"&gt;vmstat&lt;/a&gt;是Virtual Meomory Statistics（虚拟内存统计）的缩写，可对操作系统的虚拟内存、进程、CPU活动进行监控。它是对系统的整体情况进行统计，不足之处是无法对某个进程进行深入分析。
&lt;em&gt;有用的&lt;/em&gt;参数说明：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vmstat &lt;span style="color:#f92672"&gt;[&lt;/span&gt;options&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;delay &lt;span style="color:#f92672"&gt;[&lt;/span&gt;count&lt;span style="color:#f92672"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OPTIONS:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-a 显示活跃和非活跃内存
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-m 显示slabinfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-s 显示内存相关统计信息及多种系统活动数量
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-t Append timestamp to each line，在最后加个输出时间戳
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-w Wide output mode.没有加w的话，输出比较窄，可以减少对不齐问题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-bash-4.1$ vmstat -w &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;procs -------------------memory------------------ ---swap-- -----io---- --system-- -----cpu-------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r b swpd free buff cache si so bi bo in cs us sy id wa st
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;661652&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;763348&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;324&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;76100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;79&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;661652&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;763340&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;304&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;75764&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;99&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;661652&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;760744&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;244&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;78300&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;228&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3216&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;265&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;442&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/95f93eae0f6e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;pidstat
 &lt;div id="pidstat" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pidstat" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man1/pidstat.1.html" target="_blank" rel="noreferrer"&gt;pidstat&lt;/a&gt;是sysstat工具的一个命令，用于监控全部或指定进程的CPU、内存、线程、设备IO等系统资源的占用情况。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有用的&lt;/em&gt;参数说明：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pidstat OPTIONS interval &lt;span style="color:#f92672"&gt;[&lt;/span&gt; count &lt;span style="color:#f92672"&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-d :Report I/O statistics 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-u :Report CPU utilization
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r :Report page faults and memory utilization
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-w :Report task switching activity
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-p :pid&lt;span style="color:#f92672"&gt;[&lt;/span&gt;,...&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-l :Display the process command name and all its arguments.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看某进程的内存情况：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-bash-4.1$ pidstat -r -l -p &lt;span style="color:#ae81ff"&gt;2345&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Linux 2.6.32-431.el6.x86_64 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 01/06/2024 _x86_64_ &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; CPU&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;02:48:32 PM PID minflt/s majflt/s VSZ RSS %MEM Command
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;02:48:32 PM &lt;span style="color:#ae81ff"&gt;2345&lt;/span&gt; 0.23 0.00 &lt;span style="color:#ae81ff"&gt;268896&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;240&lt;/span&gt; 0.02 /pg/pg15.3/bin/postgres -D /pg/1503data &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;各类指标比较容易理解，VSZ,RSS说的都不想说了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;minflt/s：这是“minor page faults”的缩写，指的是每秒发生的“次要页面错误”的数量。当一个程序试图访问一个不在物理内存中的页面时，就会发生页面错误。如果这个页面确实在硬盘上的交换区（swap）中，那么这是一个次要页面错误（minor page fault）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;majflt/s：这是“major page faults”的缩写，指的是每秒发生的“主要页面错误”的数量。与次要页面错误不同，主要页面错误发生在程序试图访问一个不在物理内存中，且也不在硬盘上的交换区中的页面时。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;sar
 &lt;div id="sar" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sar" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man1/sar.1.html" target="_blank" rel="noreferrer"&gt;sar&lt;/a&gt;（System Activity Reporter 系统活动情况报告）是目前 Linux 上最为全面的系统性能分析工具之一，可以从多方面对系统的活动进行报告，包括：文件的读写情况、系统调用的使用情况、磁盘 I/O、CPU 效率、内存使用状况、进程活动及 IPC 有关的活动等。SAR工具是sysstat软件包的一部分。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/886494f9c001.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://www.brendangregg.com/Perf/linux_observability_sar.png" target="_blank" rel="noreferrer"&gt;https://www.brendangregg.com/Perf/linux_observability_sar.png&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;sar非常强大，man的参数介绍就有1k多行，本篇不太可能解释完（偷懒）。&lt;/p&gt;
&lt;p&gt;内存相关的参数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sar OPTIONS interval &lt;span style="color:#f92672"&gt;[&lt;/span&gt; count &lt;span style="color:#f92672"&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-B :Report paging statistics
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r :Report memory utilization statistics
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-W :Report swapping statistics.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-H :Report hugepages utilization statistics
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-s &lt;span style="color:#f92672"&gt;[&lt;/span&gt; start_time &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -e &lt;span style="color:#f92672"&gt;[&lt;/span&gt; end_time &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;示例：sar查看内存利用率
&lt;code&gt;sar -r 1 3&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kbmemfree：这个值和 free 命令中的 free 值基本一致，所以它不包括 buffer 和 cache 的空间&lt;/li&gt;
&lt;li&gt;kbmemused：这个值和 free 命令中的 used 值基本一致，所以它包括 buffer 和 cache 的空间&lt;/li&gt;
&lt;li&gt;%memused：这个值是 kbmemused 和内存总量(不包括 swap)的一个百分比&lt;/li&gt;
&lt;li&gt;kbbuffers : free 命令中的 buffer&lt;/li&gt;
&lt;li&gt;kbcached： free 命令中 cache&lt;/li&gt;
&lt;li&gt;kbcommit：保证当前系统所需要的内存，即为了确保不溢出而需要的内存(RAM + swap)&lt;/li&gt;
&lt;li&gt;%commit：这个值是 kbcommit 与内存总量(包括 swap)的一个百分比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：sar查看内存页的状态
&lt;code&gt;sar -B 1 3&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pgpgin/s：表示每秒从磁盘或SWAP置换到内存的字节数(KB)&lt;/li&gt;
&lt;li&gt;pgpgout/s：表示每秒从内存置换到磁盘或SWAP的字节数(KB)&lt;/li&gt;
&lt;li&gt;fault/s：每秒钟系统产生的缺页数，即主缺页与次缺页之和(major + minor)&lt;/li&gt;
&lt;li&gt;majflt/s：每秒钟产生的主缺页数&lt;/li&gt;
&lt;li&gt;pgfree/s：每秒被放入空闲队列中的页个数&lt;/li&gt;
&lt;li&gt;pgscank/s：每秒被 kswapd 扫描的页个数&lt;/li&gt;
&lt;li&gt;pgscand/s：每秒直接被扫描的页个数&lt;/li&gt;
&lt;li&gt;pgsteal/s：每秒钟从 cache 中被清除来满足内存需要的页个数&lt;/li&gt;
&lt;li&gt;%vmeff：每秒清除的页(pgsteal)占总扫描页(pgscank + pgscand)的百分比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：sar查看swap信息
&lt;code&gt;sar -W 1 3&lt;/code&gt;
报告说明&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pswpin/s：每秒系统换入的交换页面（swap page）数量&lt;/li&gt;
&lt;li&gt;pswpout/s：每秒系统换出的交换页面（swap page）数量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：sar查看历史内存信息
&lt;code&gt;sar -B -s &amp;quot;08:00:00&amp;quot; -e &amp;quot;10:00:00&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#不加-e表示从开始时间点到现在的信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sar -B -s &lt;span style="color:#e6db74"&gt;&amp;#34;08:00:00&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09:45:01 PM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09:46:01 PM 414429.37 395024.08 179478.63 0.07 352922.62 12003.78 4266.52 16269.42 99.99
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09:47:01 PM 879907.08 337948.43 157970.97 0.02 402290.21 0.00 0.00 0.00 0.00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09:48:01 PM 772977.43 507343.30 150255.50 0.05 466742.08 0.00 5821.28 5821.27 100.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以上pgsank表示kswapd进程介入回收内存的速度，pgscand表示直接内存回收的速度&lt;/p&gt;

&lt;h3 class="relative group"&gt;gcore
 &lt;div id="gcore" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#gcore" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://man7.org/linux/man-pages/man1/gcore.1.html" target="_blank" rel="noreferrer"&gt;gcore&lt;/a&gt;是gdb的一部分，可生成进程的core dump文件&lt;/p&gt;
&lt;p&gt;示例dump一个PostgreSQL的backend进程&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ps -ef|grep &lt;span style="color:#ae81ff"&gt;8296&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg &lt;span style="color:#ae81ff"&gt;8296&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2345&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 09:41 ? 00:00:00 postgres: pg lzldb &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; idle 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; cat /proc/8296/smaps |grep Pss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.351562
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; cat /proc/8296/smaps |grep Rss |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.445312
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt; cat /proc/8296/smaps|sed &lt;span style="color:#e6db74"&gt;&amp;#39;/zero/,/VmFlags/d&amp;#39;&lt;/span&gt; |grep Private |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{sum+=$2 };END {print sum/1024}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.0078125&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;8296进程的uss只有7.8 bytes，RSS 445 bytes。dump内存：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gcore -o /tmp/dump 8296&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;dump要花点时间，而且dump下来的文件比较大，并且会夯住进程&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;lzl &lt;span style="color:#ae81ff"&gt;8296&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; ls &lt;span style="color:#f92672"&gt;-&lt;/span&gt;lh &lt;span style="color:#f92672"&gt;/&lt;/span&gt;tmp&lt;span style="color:#f92672"&gt;/&lt;/span&gt;dump&lt;span style="color:#ae81ff"&gt;.8296&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;rw&lt;span style="color:#f92672"&gt;-&lt;/span&gt;r&lt;span style="color:#f92672"&gt;--&lt;/span&gt;r&lt;span style="color:#f92672"&gt;--&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;252&lt;/span&gt;M Jan &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt;tmp&lt;span style="color:#f92672"&gt;/&lt;/span&gt;dump&lt;span style="color:#ae81ff"&gt;.8296&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;gdb
 &lt;div id="gdb" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#gdb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://sourceware.org/gdb/current/onlinedocs/gdb" target="_blank" rel="noreferrer"&gt;gdb&lt;/a&gt;可查看内存中具体位置和内容&lt;/p&gt;
&lt;p&gt;示例查看PostgreSQL backend的缓存数据&lt;/p&gt;
&lt;p&gt;1.新开一个会话查找一个分区表，会话保持不断开&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzl &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; psql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql (&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;help&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; help.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; lzldb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; now connected &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pg&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition &lt;span style="color:#66d9ef"&gt;limit&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; appl_no &lt;span style="color:#f92672"&gt;|&lt;/span&gt; is_deleted &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_updated 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+------------+--------------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.pmap，smaps查看进程内存占用情况，找到想dump的内存段&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl 13393&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# pmap -x 13393&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13393: postgres: pg lzldb &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; idle 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Address Kbytes RSS Dirty Mode Mapping
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000400000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7864&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1204&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;..
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe2ae1b000 &lt;span style="color:#ae81ff"&gt;145968&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2164&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;176&lt;/span&gt; rw-s- zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt; ---RSS这里占用最多
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe33ca7000 &lt;span style="color:#ae81ff"&gt;96836&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r---- locale-archive
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b38000 &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b46000 &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw-s- PostgreSQL.3661351388
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b4d000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw-s- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x8001 &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fbe39b4e000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe3933000 &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rw--- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; stack &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00007fffe397d000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffffffffff600000 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; r-x-- &lt;span style="color:#f92672"&gt;[&lt;/span&gt; anon &lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl 13393&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /proc/13393/smaps |grep -A 13 zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7fbe2ae1b000-7fbe33ca7000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;12556&lt;/span&gt; /dev/zero &lt;span style="color:#f92672"&gt;(&lt;/span&gt;deleted&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Size: &lt;span style="color:#ae81ff"&gt;145968&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rss: &lt;span style="color:#ae81ff"&gt;2164&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pss: &lt;span style="color:#ae81ff"&gt;2164&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Clean: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared_Dirty: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Clean: &lt;span style="color:#ae81ff"&gt;1988&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Private_Dirty: &lt;span style="color:#ae81ff"&gt;176&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Referenced: &lt;span style="color:#ae81ff"&gt;2164&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Anonymous: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AnonHugePages: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KernelPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MMUPageSize: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; kB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;3.gdb dump memory&lt;/p&gt;
&lt;p&gt;dump内存的起始位置为smaps中的vm地址+&lt;code&gt;0x&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ gdb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;gdb&lt;span style="color:#f92672"&gt;)&lt;/span&gt; attach &lt;span style="color:#ae81ff"&gt;13393&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;gdb&lt;span style="color:#f92672"&gt;)&lt;/span&gt; dump memory /tmp/delete.dump 0x7fbe2ae1b000 0x7fbe33ca7000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;4.查看dump文件&lt;/p&gt;
&lt;p&gt;可简单通过strings 查看&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@lzl 13393&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# strings /tmp/delete.dump|grep lzl|sort|uniq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @lzlpartition_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202301_appl_no_idx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202301_date_created_idx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202306
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202306_appl_no_idx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_202306_date_created_idx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @lzlpartition_attach
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzlpartition_attach
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @nk_lzlpartition
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nk_lzlpartition
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; * from lzlpartition limit 1;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;会话只要查询了分区表，就把所有分区、索引等元数据全部缓存到backend进程中&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gdb attach [pid]会夯住进程，不要随意执行&lt;/li&gt;
&lt;li&gt;dump文件大小等于VSS，一般远大于RSS/PSS/USS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;内存小节
 &lt;div id="内存小节" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e5%ad%98%e5%b0%8f%e8%8a%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/be2156c8a394.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;references
 &lt;div id="references" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;轻松突破文件IO瓶颈：内存映射mmap技术 &lt;a href="https://blog.51cto.com/u_15481245/6582927" target="_blank" rel="noreferrer"&gt;https://blog.51cto.com/u_15481245/6582927&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一步一图带你深入理解 Linux 物理内存管理 &lt;a href="https://cloud.tencent.com/developer/article/2352771?areaId=106001" target="_blank" rel="noreferrer"&gt;https://cloud.tencent.com/developer/article/2352771?areaId=106001&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从DBA的角度系统学习一下内存管理 &lt;a href="https://mp.weixin.qq.com/s/CybzGP44dVWQN5hfFrVx7A" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/CybzGP44dVWQN5hfFrVx7A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://linux2me.wordpress.com/2017/09/15/linux-introduction-to-memory-management/" target="_blank" rel="noreferrer"&gt;https://linux2me.wordpress.com/2017/09/15/linux-introduction-to-memory-management/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Memory management in Linux &lt;a href="https://www.slideshare.net/raghusiddarth/memory-management-in-linux-11551521?from_search=2" target="_blank" rel="noreferrer"&gt;https://www.slideshare.net/raghusiddarth/memory-management-in-linux-11551521?from_search=2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux Performance Tunning Memory &lt;a href="https://www.slideshare.net/shayc1/linux-performance-tunning-memory?from_search=4" target="_blank" rel="noreferrer"&gt;https://www.slideshare.net/shayc1/linux-performance-tunning-memory?from_search=4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux内核这样学才能学会（内存篇） &lt;a href="https://mp.weixin.qq.com/s/lKKHH1MMiZbnIbDQt3-IAQ" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/lKKHH1MMiZbnIbDQt3-IAQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf" target="_blank" rel="noreferrer"&gt;https://courses.engr.illinois.edu/cs241/sp2014/lecture/09-VirtualMemory_II_sol.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux的进程虚拟地址空间 &lt;a href="https://maodanp.github.io/2019/06/02/linux-virtual-space/" target="_blank" rel="noreferrer"&gt;https://maodanp.github.io/2019/06/02/linux-virtual-space/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;redhat官方文档 &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/chap-virtualization_tuning_optimization_guide-numa" target="_blank" rel="noreferrer"&gt;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/chap-virtualization_tuning_optimization_guide-numa&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Data Processing on Modern Hardware &lt;a href="https://db.in.tum.de/teaching/ss21/dataprocessingonmodernhardware/MH_8.pdf?lang=de" target="_blank" rel="noreferrer"&gt;https://db.in.tum.de/teaching/ss21/dataprocessingonmodernhardware/MH_8.pdf?lang=de&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chapter 2 Describing Physical Memory &lt;a href="https://www.kernel.org/doc/gorman/html/understand/understand005.html" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/gorman/html/understand/understand005.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;各类命令的man手册&lt;/p&gt;
&lt;p&gt;linux强制回收内存,linux内存源码分析 - 内存回收(整体流程) &lt;a href="https://blog.csdn.net/weixin_35094083/article/details/116688112" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/weixin_35094083/article/details/116688112&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Memory compaction &lt;a href="https://lwn.net/Articles/368869/%3E" target="_blank" rel="noreferrer"&gt;https://lwn.net/Articles/368869/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;内存之旅——如何提升CMA利用率？ &lt;a href="https://ost.51cto.com/posts/10815" target="_blank" rel="noreferrer"&gt;https://ost.51cto.com/posts/10815&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The implementations of anti pages fragmentation in Linux kernel &lt;a href="https://teawater.github.io/presentation/antif.pdf" target="_blank" rel="noreferrer"&gt;https://teawater.github.io/presentation/antif.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;T H E /proc F I L E S Y S T E M &lt;a href="https://www.kernel.org/doc/Documentation/filesystems/proc.txt" target="_blank" rel="noreferrer"&gt;https://www.kernel.org/doc/Documentation/filesystems/proc.txt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The /proc/meminfo File in Linux &lt;a href="https://www.baeldung.com/linux/proc-meminfo" target="_blank" rel="noreferrer"&gt;https://www.baeldung.com/linux/proc-meminfo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;the proc filesystem &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo" target="_blank" rel="noreferrer"&gt;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;linux的/proc/{pid}/maps介绍及使用(定位内存泄漏) &lt;a href="https://blog.csdn.net/mijichui2153/article/details/123934531" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/mijichui2153/article/details/123934531&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux top命令的cpu使用率和内存使用率 &lt;a href="https://blog.csdn.net/weixin_45030965/article/details/127693042" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/weixin_45030965/article/details/127693042&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;smem memory reporting tool &lt;a href="https://www.selenic.com/smem/" target="_blank" rel="noreferrer"&gt;https://www.selenic.com/smem/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux performance optimization &lt;a href="https://feiyang233.club/post/linux/" target="_blank" rel="noreferrer"&gt;https://feiyang233.club/post/linux/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;gdb onlinedocs &lt;a href="https://sourceware.org/gdb/current/onlinedocs/gdb" target="_blank" rel="noreferrer"&gt;https://sourceware.org/gdb/current/onlinedocs/gdb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux_Core_Dumps &lt;a href="https://averageradical.github.io/Linux_Core_Dumps.pdf" target="_blank" rel="noreferrer"&gt;https://averageradical.github.io/Linux_Core_Dumps.pdf&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL FDW浅析</title><link>https://lastdba.com/2024/08/12/postgresql-fdw%E6%B5%85%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql-fdw%E6%B5%85%E6%9E%90/</guid><description>&lt;h2 class="relative group"&gt;FDW的基本概念
 &lt;div id="fdw的基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fdw%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;什么是SQL/MED？
 &lt;div id="什么是sqlmed" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afsqlmed" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;SQL/MED是为了统一异构数据源的访问方式。2003年SQL/MED加入到ISO/IEC 9075-9标准中，SQL/MED定义为通过foreign-data wrappers（fdw）或datalink（如oracle、pg的dblink）&lt;strong&gt;管理外部数据&lt;/strong&gt;的SQL标准扩展。简而言之，SQL/MED是国际SQL扩展标准。很多库已经支持SQL/MED如DB2、MariaDB、PG等等。
在没用SQL/MED时应用只能自行访问需要的数据源，并在应用层对数据进行处理：



&lt;img src="https://lastdba.com/img/csdn/4d2dae15ed42.png" alt="1" /&gt;&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;FDW的基本概念
 &lt;div id="fdw的基本概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fdw%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;什么是SQL/MED？
 &lt;div id="什么是sqlmed" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afsqlmed" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;SQL/MED是为了统一异构数据源的访问方式。2003年SQL/MED加入到ISO/IEC 9075-9标准中，SQL/MED定义为通过foreign-data wrappers（fdw）或datalink（如oracle、pg的dblink）&lt;strong&gt;管理外部数据&lt;/strong&gt;的SQL标准扩展。简而言之，SQL/MED是国际SQL扩展标准。很多库已经支持SQL/MED如DB2、MariaDB、PG等等。
在没用SQL/MED时应用只能自行访问需要的数据源，并在应用层对数据进行处理：



&lt;img src="https://lastdba.com/img/csdn/4d2dae15ed42.png" alt="1" /&gt;&lt;/p&gt;
&lt;p&gt;使用SQL/MED后，数据访问架构会更清晰



&lt;img src="https://lastdba.com/img/csdn/ab659ea2f77d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;但是，这个架构图看上去是简化了，对于数据库的IO、计算压力却提升了。这跟当今把计算从数据库剥离到应用层的思想是违背的。
当然两种方案各有优劣，有些场景下SQL/MED还是会使用到。
SQL/MED作为一个标准存在，PostgreSQL也通过FDW极好的支持了SQL/MED标准。&lt;/p&gt;

&lt;h3 class="relative group"&gt;什么是FDW？
 &lt;div id="什么是fdw" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%affdw" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0c0845d79809.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;postgresql从开始9.1支持fdw。用户可以通过常规的SQL语句访问外部数据（foreign data）。foreign data通过foreign data wrapper（fdw）来访问。postgresql数据库中的fdw本身是一个library ，因为不同的外部数据对应这不同的fdw插件，所以我们也常说说它是fdw插件。
pg中的FDW功能十分强大，不仅支持多种数据源，还对数据访问做了优化，甚至可以用来做“超出预期”的事情，比如集群功能的实现。&lt;/p&gt;

&lt;h3 class="relative group"&gt;安装与下载
 &lt;div id="安装与下载" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ae%89%e8%a3%85%e4%b8%8e%e4%b8%8b%e8%bd%bd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;基本上每种数据库、数据类型都有各自的fdw插件，访问oracle库有oracle_fdw，访问mysql库有mysql_fdw等等。fdw插件可以直接安装或者下载安装：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;已包含在extension中的fdw。有file_fdw、postgres_fdw、cstore_fdw&lt;/li&gt;
&lt;li&gt;其他的fdw插件可以在PGXN或者wiki上下载，比如：oralce_fdw、mysql_fdw、json_fdw。注意仔细阅读readme，了解不同fdw的限制和使用规则。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;fdw插件下载地址：&lt;a href="https://pgxn.org/tag/fdw/" target="_blank" rel="noreferrer"&gt;https://pgxn.org/tag/fdw/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;更多的fdw（大部分是beta版）:&lt;a href="https://wiki.postgresql.org/wiki/Foreign_data_wrappers" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Foreign_data_wrappers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;自行编写fdw。https://www.postgresql.org/docs/current/fdwhandler.html&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;pg中fdw相对dblink的优势
 &lt;div id="pg中fdw相对dblink的优势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e4%b8%adfdw%e7%9b%b8%e5%af%b9dblink%e7%9a%84%e4%bc%98%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg库也有dblink。fdw和dblink在功能上是很类似的都是访问外部表。但是fdw有更多优势&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fdw支持更多的数据源（非常非常多）。dblink只支持postgresql数据库，相当于fdw的其中一个插件postgres_fdw功能（实际上postgres_fdw要强的多）&lt;/li&gt;
&lt;li&gt;对开发透明。可以像访问普通表一样访问外部表&lt;/li&gt;
&lt;li&gt;更符合标准SQL语法&lt;/li&gt;
&lt;li&gt;在很多场景下有更好的性能&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;The functionality provided by this module overlaps substantially with the functionality of the older &lt;a href="https://www.postgresql.org/docs/15/dblink.html" title="F.12. dblink" target="_blank" rel="noreferrer"&gt;dblink&lt;/a&gt; module. But &lt;code&gt;postgres_fdw&lt;/code&gt; provides more transparent and standards-compliant syntax for accessing remote tables, and can give better performance in many cases.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;总之，fdw强于dblink插件，基本上可以把dblink遗忘了。&lt;/p&gt;

&lt;h2 class="relative group"&gt;fdw的4个对象
 &lt;div id="fdw的4个对象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fdw%e7%9a%844%e4%b8%aa%e5%af%b9%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;不同的fdw有不同的用法，但基本都需要创建4个对象&lt;strong&gt;foreign data wrapper&lt;/strong&gt;（包装器），&lt;strong&gt;server&lt;/strong&gt;（外部服务），&lt;strong&gt;user mapping&lt;/strong&gt;（用户映射），&lt;strong&gt;foreign table&lt;/strong&gt;（外部表）。其中有些对象不是必须的，比如file_fdw就可以没有user mapping，而关系型数据库的fdw一般都需要创建user mapping。&lt;/p&gt;

&lt;h3 class="relative group"&gt;foreign data wrapper
 &lt;div id="foreign-data-wrapper" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#foreign-data-wrapper" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在CREATE EXTENSION创建好相应的fdw插件后，foreign data wrapper就自动建好了。
比如创建一个file_fdw extension，其对应的foreign data wrapper自动创建好。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; extension file_fdw;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; EXTENSION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;dx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Version&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Schema&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------+---------+------------+------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_fdw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;foreign&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; wrapper &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; flat file &lt;span style="color:#66d9ef"&gt;access&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;##&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.foreign_data_wrappers;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foreign_data_wrapper_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_data_wrapper_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; authorization_identifier &lt;span style="color:#f92672"&gt;|&lt;/span&gt; library_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_data_wrapper_language 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------+---------------------------+--------------------------+--------------+-------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; file_fdw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;也可以不使用插件，自行创建一个外部数据包装器，参考&lt;a href="https://www.postgresql.org/docs/13/sql-createforeigndatawrapper.html" target="_blank" rel="noreferrer"&gt;CREATE FOREIGN DATA WRAPPER&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;server
 &lt;div id="server" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#server" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;CREATE SERVER可以创建一个外部服务，相当于指定了数据来源。其中OPTIONS的语法因不同的foreign-data wrapper而不同，比如file_fdw,postgres_fdw的OPTION语法肯定是不一样的，这时就要读fdw插件的readme或者官方文档了。例如
创建一个file_fdw的外部服务名叫fileserver:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; SERVER fileserver &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt; WRAPPER file_fdw;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;创建一个postgres_fdw的外部服务名叫pgserver，服务来自172.0.0.1:5432 pg实例上的lzldb库：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; SERVER pgserver &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt; WRAPPER postgres_fdw &lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;host&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;172.0.0.1&amp;#39;&lt;/span&gt;, dbname &lt;span style="color:#e6db74"&gt;&amp;#39;lzldb&amp;#39;&lt;/span&gt;, port &lt;span style="color:#e6db74"&gt;&amp;#39;5432&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看server：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.foreign_servers;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foreign_server_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_data_wrapper_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_data_wrapper_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_version &lt;span style="color:#f92672"&gt;|&lt;/span&gt; authorization_identifier 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------+---------------------+------------------------------+---------------------------+---------------------+------------------------+--------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pgserver &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres_fdw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; fileserver &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; file_fdw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;user mapping
 &lt;div id="user-mapping" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#user-mapping" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;user mapping定义了外部服务用户和本地用户的对应关系。所以一般关系型数据库类的fdw都有user mapping，而file这类的fdw没有用户定义就不需要创建这个。
例如用刚才的pgserver创建一个user mapping&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USER&lt;/span&gt; MAPPING &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; localuser SERVER pgserver &lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;remoteuser&amp;#39;&lt;/span&gt;, password &lt;span style="color:#e6db74"&gt;&amp;#39;mypasswd&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看user mapping&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.user_mappings;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; authorization_identifier &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_name 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------+------------------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; localuser &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pgserver&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;foreign table
 &lt;div id="foreign-table" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#foreign-table" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;foreign table相当于在本地映射了远程表，然后就可以像普通表一样进行访问。因为涉及本地对象了，OPTION很多，所以全语法有些复杂，可参考&lt;a href="https://www.postgresql.org/docs/current/sql-createforeigntable.html" target="_blank" rel="noreferrer"&gt;CREATE FOREIGN TABLE&lt;/a&gt;，简单点那么在本地建一个远程对应的表就可以了。
而因fdw的不同语法也有所不同，此处不多做展示了。
举例两个常见的创建foreign table的方式：创建和导入。
创建一个外部表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; localtable (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id char(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name varchar(&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SERVER pgserver &lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;remotetable&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一个个创建foreign table比较麻烦，可以一次把外部schema下的table全部导入&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMPORT &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; remoteschema &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; SERVER pgserver &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; localschema;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查看foreign table&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; information_schema.foreign_tables; &lt;span style="color:#75715e"&gt;--能直观看到foreign表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_foreign_server; &lt;span style="color:#75715e"&gt;--不太直观，但展示了option选项&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;fdw的使用
 &lt;div id="fdw的使用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fdw%e7%9a%84%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;查看外部表信息
 &lt;div id="查看外部表信息" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9f%a5%e7%9c%8b%e5%a4%96%e9%83%a8%e8%a1%a8%e4%bf%a1%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;psql自带的快捷命令比较清晰，可以简单的查看外部表的4个对象，不过要注意search_path的设置&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;psql命令&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;\des&lt;/td&gt;
 &lt;td&gt;list foreign servers&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;\deu&lt;/td&gt;
 &lt;td&gt;list uses mappings&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;\det&lt;/td&gt;
 &lt;td&gt;list foreign tables&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;\dtE&lt;/td&gt;
 &lt;td&gt;list both local and foreign tables&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;外部表对象的视图/表比较乱，稍微梳理一下&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;foreign data wrapper 表/视图&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema._pg_foreign_data_wrappers&lt;/td&gt;
 &lt;td&gt;信息较全&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.foreign_data_wrappers&lt;/td&gt;
 &lt;td&gt;信息较少&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.foreign_data_wrapper_options&lt;/td&gt;
 &lt;td&gt;针对性的查foreign data wrapper的option&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_foreign_data_wrapper&lt;/td&gt;
 &lt;td&gt;信息略少，但是有权限信息！权限信息其他几个视图都没有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;foreign server 表/视图&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema._pg_foreign_servers&lt;/td&gt;
 &lt;td&gt;信息较全&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.foreign_servers&lt;/td&gt;
 &lt;td&gt;信息较少&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.foreign_server_options&lt;/td&gt;
 &lt;td&gt;针对性的查option，不是一个server一条记录，而是一个option一个记录&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_foreign_server&lt;/td&gt;
 &lt;td&gt;信息较少，基表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;user mapping 表/视图&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema._pg_user_mappings&lt;/td&gt;
 &lt;td&gt;较全的user mapping信息&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.user_mappings&lt;/td&gt;
 &lt;td&gt;信息较少&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.user_mapping_options&lt;/td&gt;
 &lt;td&gt;针对性的查um的option&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_user_mappings&lt;/td&gt;
 &lt;td&gt;信息比information_schema._pg_user_mappings略少一点。这个视图可以被没有权限的用户查看，密码会被展示为null&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;pg_user_mapping&lt;/td&gt;
 &lt;td&gt;信息较少，基表，主要是option。没有访问权限的用户是查看不了的&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;foreign table 表/视图&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema._pg_foreign_tables&lt;/td&gt;
 &lt;td&gt;信息较全，展示所有外部表信息&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema._pg_foreign_table_columns&lt;/td&gt;
 &lt;td&gt;展示了列与列的对应关系&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;information_schema.foreign_table_options&lt;/td&gt;
 &lt;td&gt;针对性的展示foreign table的option&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;foreign_tables&lt;/td&gt;
 &lt;td&gt;信息较少，基表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些视图/表看上去挺乱的，但是实际上结构还比较清楚。4种对象的数据字典基表都基本都是一个逻辑



&lt;img src="https://lastdba.com/img/csdn/6805aee46c58.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg_xxx是基表，是4个对象的基础信息来源&lt;/li&gt;
&lt;li&gt;information_schema._pg_xxx 关联了pg_xxx基表和其他一些信息，information_schema._pg_xxx是一个汇总的视图，信息比较全面&lt;/li&gt;
&lt;li&gt;information_schema.xxx是information_schema._pg_xxx上的视图，信息少一点&lt;/li&gt;
&lt;li&gt;information_schema.xxx_options针对性展示option信息，信息仅来自于全量视图information_schema._pg_xxx&lt;/li&gt;
&lt;li&gt;一个特殊的视图pg_user_mappings，无权限用户也可以使用&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;注意权限问题
 &lt;div id="注意权限问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b3%a8%e6%84%8f%e6%9d%83%e9%99%90%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果一路使用postgres超级用户去创建外部表，基本上不会遇到什么问题。但是在生产环境中通常应用用户不会是超级用户。所以，权限是非常重要的。它不仅重要而且还比较麻烦，所以使用普通用户做实验很重要（任何实验都是）。pg的权限像闯关打BOSS，缺少任何一环的权限都是不行的。
权限问题需要注意以下几点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;foreign data wrapper，server，user mapping的owner都是创建者，必须各自授权用户usage权限或者是owner本身才可以使用&lt;/li&gt;
&lt;li&gt;访问远端数据源，需要使用合适权限用户，也就是在user mapping那一步指定合适的远端库登陆用户&lt;/li&gt;
&lt;li&gt;本地库在创建/导入外部表后，对象被看成本地对象（只有数据字典），所以pg对本地对象的访问权限体系也得合适。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;权限可以参考下面postgres_fdw访问外部表的示例&lt;/p&gt;

&lt;h3 class="relative group"&gt;fdw使用示例
 &lt;div id="fdw使用示例" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fdw%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;全世界已有成百上千种数据源有了相应的FDW实现，各种关系型数据库、nosql数据库、各种类型的文件、Web Service、列式存储、大数据等等。这里介绍几种常见的fdw。&lt;/p&gt;

&lt;h4 class="relative group"&gt;postgres_fdw的使用
 &lt;div id="postgres_fdw的使用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgres_fdw%e7%9a%84%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;这个几乎是最常用也最强大的fdw，可以在本地库中访问外部PostgresSQL数据库。当然也可以用来自我访问，这个功能是很重要的，因为：&lt;strong&gt;PGSQL内部不能跨database访问！&lt;/strong&gt; 如果要解决这个问题，一个比较好的办法就是用fdw实现本地实例跨database访问，通过外部连接实现自己访问自己···&lt;/p&gt;
&lt;p&gt;这里是一个用postgres_fdw实现跨database访问的例子
一个实例里面有两个database，aka和bkb。你不能通过一个sql同时查询aka和bkb库，database在pg中是逻辑隔绝的，有点像oracle 12c的pdb&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[lzl&lt;span style="color:#f92672"&gt;@&lt;/span&gt;postgres]&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aka &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;Tc&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CTc&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bkb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.UTF&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;Tc&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CTc&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;虽然2个库都是本地库，但是在使用fdw的时候还是需要本地库远程库的概念。这里我们把aka当作本地库，bkb当作远程库，实现在aka库中访问bkb库的表，并处理权限问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.安装fdw插件&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; aka
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; extension postgres_fdw;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;注意：插件是库级别的，需要切到本地库上&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.用户授权&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;usage&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;foreign&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; wrapper postgres_fdw &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; akadata;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3.创建server&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; aka akadata
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; SERVER bkb_server &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt; WRAPPER postgres_fdw &lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;host&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;, port &lt;span style="color:#e6db74"&gt;&amp;#39;5432&amp;#39;&lt;/span&gt;, dbname &lt;span style="color:#e6db74"&gt;&amp;#39;bkb&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;4.创建user mapper&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USER&lt;/span&gt; MAPPING &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; akadata SERVER bkb_server &lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;bkbdata&amp;#39;&lt;/span&gt;, password &lt;span style="color:#e6db74"&gt;&amp;#39;bkbpasswd&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;5.aka库下创建schema，schema授权给akadata用户&lt;/strong&gt;
因为担心有重复的表名，导入到另一个schema里&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; aka postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;schema&lt;/span&gt; bkb;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;usage&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;schema&lt;/span&gt; bkb &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; akadata;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--GRANT select ON ALL TABLES IN SCHEMA bkb TO akadata;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;privileges&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;schema&lt;/span&gt; bkb &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; akadata;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;6.导入bkb表&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; aka akadata&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;导入整个schema&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMPORT &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; SERVER bkb_server &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; bkb;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;导入单个表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IMPORT &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LIMIT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (tab1) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; SERVER bkb_server &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; bkb &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;7.查看外部表&lt;/strong&gt;
*&lt;em&gt;注意 search_path，导入完成后\d可能看不到外部表&lt;/em&gt;
select * from bkb.tab1直接查询可以查到外部表数据，或者基表或视图查看所有的外部表信息&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.foreign_tables;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foreign_table_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_table_schema &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_table_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; foreign_server_name 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------+----------------------+-------------------------------------+------------------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aka &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bkb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tab1 		&lt;span style="color:#f92672"&gt;|&lt;/span&gt; aka &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bkb_server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;file_fdw的使用
 &lt;div id="file_fdw的使用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#file_fdw%e7%9a%84%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;file_fdw插件为pg提供了访问外部文件的能力，目前只提供了只读能力。file_fdw已经在contrib中，可以直接&lt;code&gt;CREATE EXTESION&lt;/code&gt;安装使用。外部文件必须是符合COPY规则的。
来个经典的把pg的输出日志映射成外部表的例子，脚本来自&lt;a href="https://www.postgresql.org/docs/current/file-fdw.html" target="_blank" rel="noreferrer"&gt;官方文档&lt;/a&gt; (注意官方文档和pgsql库的版本，pgsql的版本不同日志输出略有不同，所以建的外部表字段有一点不一样）
&lt;strong&gt;1.创建file_fdw插件&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; EXTENSION file_fdw;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2.创建外部服务&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; SERVER fileserver &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt; WRAPPER file_fdw;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3.创建外部表&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; pglog (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log_time &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_name text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; database_name text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; process_id integer,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; connection_from text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session_id text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session_line_num bigint,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command_tag text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session_start_time &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtual_transaction_id text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transaction_id bigint,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_severity text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sql_state_code text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; detail text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hint text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; internal_query text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; internal_query_pos integer,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query_pos integer,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;location&lt;/span&gt; text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; application_name text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) SERVER fileserver
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;OPTIONS&lt;/span&gt; ( filename &lt;span style="color:#e6db74"&gt;&amp;#39;pg_log/postgresql-07-06.csv&amp;#39;&lt;/span&gt;, format &lt;span style="color:#e6db74"&gt;&amp;#39;csv&amp;#39;&lt;/span&gt; );&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;4.查看日志表&lt;/strong&gt;
直接在库中查看映射的日志表，很方便查到报错信息&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; user_name,database_name,process_id,error_severity,message &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pglog &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; error_severity&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;LOG&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; database_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; process_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; error_severity &lt;span style="color:#f92672"&gt;|&lt;/span&gt; message 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+---------------+------------+----------------+-----------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; appuser1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; db1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;102349&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ERROR &lt;span style="color:#f92672"&gt;|&lt;/span&gt; value too long &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; appuser1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; db1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;55378&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ERROR &lt;span style="color:#f92672"&gt;|&lt;/span&gt; value too long &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; appuser2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; db2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;219377&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ERROR &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relation &lt;span style="color:#e6db74"&gt;&amp;#34;dual&amp;#34;&lt;/span&gt; does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; exist&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;postgres_fdw深入
 &lt;div id="postgres_fdw深入" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgres_fdw%e6%b7%b1%e5%85%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;postgres_fdw性能优化
 &lt;div id="postgres_fdw性能优化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgres_fdw%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;跟绝大多数fdw插件不同，postgres_fdw是PostgreSQL Global Development Group维护的官方插件，其源码包含contrib中。因为外部服务的功能、结构的不同，一些功能比如获得远程库的访问代价、某些场景下的聚合下推等在其他fdw中是难以实现的。但是在postgres_fdw中却可以做到，官方对 postgres_fdw做了非常多的优化，其功能已经非常强大。&lt;/p&gt;

&lt;h4 class="relative group"&gt;SQL执行过程
 &lt;div id="sql执行过程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sql%e6%89%a7%e8%a1%8c%e8%bf%87%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2d6d90fc0f63.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;解析器通过外部表的定义生成查询树&lt;/li&gt;
&lt;li&gt;计划器连接到外部服务foreign server&lt;/li&gt;
&lt;li&gt;获得cost信息。如果use_remote_estimate是true时（默认），计划器会在远程库执行explain获得访问代价（第（3）步）；如果是false，那么不会去执行explain（第（3）步）而是在本地进行计算。&lt;/li&gt;
&lt;li&gt;deparse生成远程库SQL文本。&lt;strong&gt;fdw直接通过发送SQL文本的方式访问远程库对象&lt;/strong&gt;，计划器会生成远程库执行的sql文本。执行计划&lt;code&gt;Remote SQL&lt;/code&gt;部分可直接看见deparse生成的SQL文本：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ((a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;发送SQL语句并接收数据。远程库接收到SQL后自行执行，并按fetch_size（默认100行）返回结果给本地库&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 class="relative group"&gt;代价估算
 &lt;div id="代价估算" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%a3%e4%bb%b7%e4%bc%b0%e7%ae%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;postgres_fdw可以将远程库的对象访问代价传递给本地库，以计算整个SQL的执行计划代价。然而仅仅返回远程库估算的代价是不够的，还需要考虑远程访问本身的成本。postgres_fdw提供了3个OPTIONS设置来调整外部表的代价估算：
&lt;strong&gt;use_remote_estimate&lt;/strong&gt;：设置为true时，计划器会去远程库explain获得估算的代价，并加上fdw_startup_cost和fdw_tuple_cost的代价计算总的访问代价；如果为false（默认），planner在本地计算并加上fdw_startup_cost和fdw_tuple_cost计算出总的访问代价。本地的外部表统计信息可能与实际不一致。
&lt;strong&gt;fdw_startup_cost&lt;/strong&gt;：外部表的启动代价，默认100。代表在外部服务上创建连接、解析、生成计划的代价
&lt;strong&gt;fdw_tuple_cost&lt;/strong&gt;：扫描外部表每个tuple的额外代价，默认0.01。代表数据传输的代价，延时越高这个设置应该设置的越高。&lt;/p&gt;
&lt;p&gt;默认设置下，外部表的startup cost为100：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.students;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; students (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;119&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;301&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;248&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;聚合下推
 &lt;div id="聚合下推" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%81%9a%e5%90%88%e4%b8%8b%e6%8e%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;聚合下推是将运算放在远程库执行，本地库直接获得远程库的执行结果。如果没有聚合下推，数据需要全部返回给本地库并由本地库进行计算，这会增加数据传输对SQL执行效率的影响，且会加大本地库的计算负担。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(环境中的bkb.*都是外部表，本地表都是public.*)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;谓词下推&lt;/strong&gt;
postgres_fdw支持where下推，下推后不需要返回全部数据到本地库&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; f1.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 f1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; f1.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1 f1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ((a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg直接将整个语句发送给远程库执行，where在远程库进行过滤。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d307861ec543.png" alt="在这里插入图片描述" /&gt;



&lt;img src="https://lastdba.com/img/csdn/111a431a83e3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;sort下推&lt;/strong&gt;
postgres_fdw支持sort下推，同样可以发送sort给远程库执行。注意sort的默认模式。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; f1.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 f1 &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt; nulls &lt;span style="color:#66d9ef"&gt;first&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1 f1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;DESC&lt;/span&gt; NULLS &lt;span style="color:#66d9ef"&gt;FIRST&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;join下推&lt;/strong&gt;
一些无法下推的join不能在远程库进行计算，比如本地表join外部表，只能直接把外部表的查询结果拿到本地进行join&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; f1.a,l2.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 f1,tab1 l2 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; f1.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;l2.a;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: f1.a, l2.a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (l2.a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f1.a)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 l2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: l2.a, l2.b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: f1.a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1 f1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: f1.a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;本地表join外部表时，外部表只能全部访问（没有其他where的情况下）返回给本地库，然后又本地库做join操作&lt;/p&gt;
&lt;p&gt;两个表都是外部表时可以下推到远程库去执行join操作&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; f1.a,f1.b &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 f1 &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; bkb.tab2 f2 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; f1.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;f2.a;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: f1.a, f1.b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Relations: (bkb.tab1 f1) &lt;span style="color:#66d9ef"&gt;LEFT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; (bkb.tab2 f2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; r1.a, r1.b &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 r1 &lt;span style="color:#66d9ef"&gt;LEFT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab2 r2 &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; (((r1.a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; r2.a))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Remote SQL直接将join发送给远程库去执行，本地库只需要等待返回结果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;聚合函数下推&lt;/strong&gt;
支持聚合函数下推，聚合函数必须是&lt;code&gt;IMMUTABLE&lt;/code&gt;的&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; b,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;avg&lt;/span&gt;(a) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; b;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; GroupAggregate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: b, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;avg&lt;/span&gt;(a)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: tab1.b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: a, b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; a, b &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;ASC&lt;/span&gt; NULLS &lt;span style="color:#66d9ef"&gt;LAST&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;某些场景并不支持，比如having语句只能在本地filter，Remote SQL没有传递having文本到远程库&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;,costs &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; b,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bkb.tab1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;having&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; GroupAggregate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: b, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: tab1.b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Foreign&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; bkb.tab1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Output&lt;/span&gt;: a, b
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Remote &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.tab1 &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;ASC&lt;/span&gt; NULLS &lt;span style="color:#66d9ef"&gt;LAST&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;其他特性
 &lt;div id="其他特性" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b6%e4%bb%96%e7%89%b9%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;远程执行相关OPTION设置
 &lt;div id="远程执行相关option设置" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%9c%e7%a8%8b%e6%89%a7%e8%a1%8c%e7%9b%b8%e5%85%b3option%e8%ae%be%e7%bd%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;默认情况下，只有where中的内置运算符和函数能在远程服务执行。不是内置运算符的只能在远程库fetch数据到本地，然后在本地计算。如果内置运算符和函数能在远程执行，且运行结果和本地一致，性能会有提升。
&lt;strong&gt;extensions&lt;/strong&gt;：由用户来指定哪些fdw extension可以用“远程计算”。只能在server层设置。
&lt;strong&gt;fetch_size&lt;/strong&gt;：从远程库获取数据时，一次fetch的数据行数，默认为100。可以在server或table层设置。
更新设置
&lt;strong&gt;updatable&lt;/strong&gt;：默认情况下postgres_fdw的外部表都是可以更新的。不过可以用updatable选项来设置。如果外部表本身就是不可更新的，可以在表级设置updatable为false，使其直接在本地报错。
&lt;strong&gt;truncatable&lt;/strong&gt;：pg14开始postgres_fdw支持truncate外部表，并提供&lt;code&gt;truncatable&lt;/code&gt;选项控制外部表是否可以truncate，该选项默认为true。&lt;/p&gt;

&lt;h4 class="relative group"&gt;连接管理
 &lt;div id="连接管理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%9e%e6%8e%a5%e7%ae%a1%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;在会话发起第一次外部表访问时，会建立与远程库的连接，只要本地会话没有断开，就会一直使用这个连接。如果使用多个user mapping则会为每个用户映射建立连接。
pg14开始&lt;code&gt;keep_connections&lt;/code&gt;选项可以控制这个特性。keep_connections默认为on，表示会话后续可以重用这个连接；为off时事务结束边断开连接。
pg14开始 &lt;code&gt;postgres_fdw_get_connections()&lt;/code&gt;可查看连接情况&lt;/p&gt;

&lt;h4 class="relative group"&gt;事务管理
 &lt;div id="事务管理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%ae%a1%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;fdw的事务特性需要注意以下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;远程库按本地库发送的文本执行SQL&lt;/li&gt;
&lt;li&gt;本地有SERIALIZABLE隔离级别时，远程也是SERIALIZABLE隔离级别，否则远程是REPEATABLE READ隔离级别&lt;/li&gt;
&lt;li&gt;本地事务提交或回滚时，远程事务也提交或回滚&lt;/li&gt;
&lt;li&gt;fdw不支持2pc事务
因为不支持分布式2PC事务，可能导致事务部分提交。比如以下示例，远程库即使更新失败，本地库的update仍然可以完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--开启事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt; ; &lt;span style="color:#75715e"&gt;--本地更新数据，成功
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; bkb.tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--远程更新数据，失败
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42703&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;c&amp;#34;&lt;/span&gt; does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; exist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LINE &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; bkb.tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--事务提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; b 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;无分布式锁管理
 &lt;div id="无分布式锁管理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%97%a0%e5%88%86%e5%b8%83%e5%bc%8f%e9%94%81%e7%ae%a1%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;fdw没有分布式锁管理，所以也没有分布式死锁检测机制。&lt;/p&gt;
&lt;p&gt;如果在本地库产生死锁并且deadlock_timeout设置了一个值（默认1s），会话会产生报错
本地表死锁检测：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;session 1&lt;/th&gt;
 &lt;th style="text-align: left"&gt;session 2&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; begin;&lt;br&gt;BEGIN&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; begin;&lt;br&gt;BEGIN&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab2 set b=1;&lt;br&gt;UPDATE 1&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab1 set b=1;&lt;br&gt;UPDATE 1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab1 set b=1;&lt;br&gt;--等待&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab2 set b=1;&lt;br&gt;&lt;code&gt;sql ERROR: 40P01: deadlock detected&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;外部表不会检测死锁：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;session a&lt;/th&gt;
 &lt;th style="text-align: left"&gt;session b&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; begin;&lt;br&gt;BEGIN&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; begin;&lt;br&gt;BEGIN&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update bkb.tab2 set b=1;&lt;br&gt;UPDATE 1&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab1 set b=1;&lt;br&gt;UPDATE 1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update tab1 set b=1;&lt;br&gt;--等待&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;br&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;=&amp;gt; update bkb.tab2 set b=1;&lt;br&gt;--等待&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 class="relative group"&gt;异步执行
 &lt;div id="异步执行" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bc%82%e6%ad%a5%e6%89%a7%e8%a1%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg14开始支持postgres_fdw异步执行。在执行计划中存在多个append节点时，可以并行执行，这样能提高多个外部表访问时的性能。
异步执行只能在有多个会话时才能产生，也就是说多个user mapping的情况下才会有异步执行。
&lt;code&gt;async_capable&lt;/code&gt;选项控制异步执行特性，默认为false。另外&lt;code&gt;enable_async_append&lt;/code&gt;参数也要打开，默认on。&lt;/p&gt;
&lt;p&gt;这个特性十分重要，因为异步执行几乎是sharding所必要的特性。它可以实现在扫描每个sharding分片时并行的执行，既同时使用多个分片上的资源进行数据访问，提高sharding数据的访问效率。&lt;/p&gt;

&lt;h4 class="relative group"&gt;并行提交
 &lt;div id="并行提交" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%b9%b6%e8%a1%8c%e6%8f%90%e4%ba%a4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg15开始支持postgres_fdw并行提交。远程事务随着本地事务提交而提交，在没有并行提交/回滚时，pg只能串行的提交/回滚各个远程的事务（子事务同样也是顺序提交）。当有很多外部事务关联本地事务时，所有外部事务顺序提交完这种模式效率较低。
此时可以使用并行提交特性，由&lt;code&gt;parallel_commit&lt;/code&gt;和&lt;code&gt;parallel_abort&lt;/code&gt;选项控制，分别代表并行提交事务和并行关闭事务，默认均为false。
并行提交对性能的提升参考这篇&lt;a href="https://www.percona.com/blog/parallel-commits-for-transactions-using-postgres_fdw-on-postgresql-15/" target="_blank" rel="noreferrer"&gt;文章&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;postgres_fdw的版本历史
 &lt;div id="postgres_fdw的版本历史" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#postgres_fdw%e7%9a%84%e7%89%88%e6%9c%ac%e5%8e%86%e5%8f%b2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;postgres_fdw非常强大，并且不断的在版本更新中提升。以下表格汇总了各个版本相关postgres_fdw的需要关注的功能提升：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;版本&lt;/th&gt;
 &lt;th style="text-align: left"&gt;release支持说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;9.3&lt;/td&gt;
 &lt;td style="text-align: left"&gt;postgres_fdw发布&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9.6&lt;/td&gt;
 &lt;td style="text-align: left"&gt;支持下推join，sort，update，delete；&lt;br&gt;支持fetch_size设置&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td style="text-align: left"&gt;可下推聚合函数到外部服务；&lt;br&gt;下推更多场景下的join&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td style="text-align: left"&gt;可下推算子到分区表上；&lt;br&gt;UPDATE/DELETE语句的join可以下推到外部服务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12&lt;/td&gt;
 &lt;td style="text-align: left"&gt;下推更多场景下的order by/limit子句；&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;13&lt;/td&gt;
 &lt;td style="text-align: left"&gt;加强权限密码认证功能；&lt;br&gt;pg_dump可导出外部表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;14&lt;/td&gt;
 &lt;td style="text-align: left"&gt;当一个查询有多个外部表时，提供并行扫描能力，由async_capable控制；&lt;br&gt;支持批量插入；&lt;br&gt;postgres_fdw_get_connections()查看当前外部连接情况；&lt;br&gt;支持truncate外部表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;15&lt;/td&gt;
 &lt;td style="text-align: left"&gt;下推CASE表达式；&lt;br&gt;支持并行提交，由server选项parallel_commit控制&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td style="text-align: left"&gt;postgres_fdw可以中断并行事务；&lt;br&gt;支持外部表analyze_sampling设置；&lt;br&gt;可通过batch_size选项控制COPY数据到外部表；&lt;br&gt;允许外部表truncate触发器&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 class="relative group"&gt;sharding的实现
 &lt;div id="sharding的实现" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sharding%e7%9a%84%e5%ae%9e%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;基于FDW实现sharding
 &lt;div id="基于fdw实现sharding" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%9f%ba%e4%ba%8efdw%e5%ae%9e%e7%8e%b0sharding" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;有许多分支基于PostgreSQL已经实现了sharding功能，比如XC/XL、Citus等等，但是PostgreSQL本身是单实例数据库，目前还没有原生支持sharding。并且虽然很多分支实现了sharding但也会造成其版本跟PostgreSQL社区版本存在lag。
由于SQL/MED本身是为了访问外部数据而定义的标准，所以postgres_fdw可以通过访问外部实例的方式实sharding功能。基于FDW实现sharding的方案目前来看是对代码改动最小的，并且很多分支也是基于这个方案来实现。
所以PostgreSQL原生支持sharding一直呼声很高，社区也考虑过用postgres_fdw实现sharding功能



&lt;img src="https://lastdba.com/img/csdn/50d6661663a4.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;实现sharding的核心功能
 &lt;div id="实现sharding的核心功能" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ae%9e%e7%8e%b0sharding%e7%9a%84%e6%a0%b8%e5%bf%83%e5%8a%9f%e8%83%bd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;一个能够使用的sharding，需要具备一些特性，以下列举几个sharding功能较为受关注的特性，其中一些功能已经在postgres_fdw实现，一些仍然to-do：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 分区管理。SQL/MED拥有透明访问特点，如果sharding在分区表上实现，sharding以分区的方式附在分区表上，访问分区也是透明的，这样一来业务就完全不需要关注数据路由就可以在数据库层实现sharding。现在原生分区也可以加入外部表。&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 分区优化。把外部表当成分区可以使用分区表上的优化功能，比如分区裁剪、PARTITION WISE JOIN等功能可以极大的降低访问开销。&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 聚合下推。把数据全部采集到本地进行计算明显不是sharding的初衷，把计算放到各自的远程库分片上执行可以充分利用资源，所以DML、谓词下推、聚合函数下推等对于sharding来说很重要。&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 并行扫描。在没有并行扫描时，多个sharding只能顺序执行；有并行扫描后分片可以同时运行。该特性已在pg14实现&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 2PC事务。2PC事务可以保证分布式事务的原子性，如果没有2PC那么可能出现部分分片数据更新，部分分片更新失败的情况。该特性也比较重要，fdw目前还不支持2PC事务。&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 分片管理。外部表的分区不是自动添加的，只能手动完成创建和添加到分区表的操作。如果分区特别多，管理起来会很麻烦&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 全局事务。需要一些机制来保证全局事务一致性，比如全局时钟、全局快照管理等等&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 分布式锁。需要更强大的分布式锁机制&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 批量写入。DML/COPY等分发到分片的操作需要支持批量写入。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;总结
 &lt;div id="总结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL的FDW功能由SQL/MED标准而来，用来访问外部数据，并且支持非常多类型的数据访问&lt;/li&gt;
&lt;li&gt;FDW有4个基本对象：foreign data wrapper，server，user mapping，foreign table&lt;/li&gt;
&lt;li&gt;postgres_fdw有很多功能提升和性能优化，可以将算子下推到远程库&lt;/li&gt;
&lt;li&gt;基于postgres_fdw可以实现sharding功能，有些功能还有待完善&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;参考
 &lt;div id="参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/pgsql04.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql04.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/13/postgres-fdw.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/postgres-fdw.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/file-fdw.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/file-fdw.html&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/WIP_PostgreSQL_Sharding" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/WIP_PostgreSQL_Sharding&lt;/a&gt;
&lt;a href="https://www.percona.com/blog/postgres_fdw-enhancement-in-postgresql-14/" target="_blank" rel="noreferrer"&gt;https://www.percona.com/blog/postgres_fdw-enhancement-in-postgresql-14/&lt;/a&gt;
&lt;a href="https://www.percona.com/blog/foreign-data-wrappers-postgresql-postgres_fdw/" target="_blank" rel="noreferrer"&gt;https://www.percona.com/blog/foreign-data-wrappers-postgresql-postgres_fdw/&lt;/a&gt;
&lt;a href="https://www.percona.com/blog/parallel-commits-for-transactions-using-postgres_fdw-on-postgresql-15/" target="_blank" rel="noreferrer"&gt;https://www.percona.com/blog/parallel-commits-for-transactions-using-postgres_fdw-on-postgresql-15/&lt;/a&gt;
&lt;a href="https://www.enterprisedb.com/blog/postgresql-aggregate-push-down-postgresfdw" target="_blank" rel="noreferrer"&gt;https://www.enterprisedb.com/blog/postgresql-aggregate-push-down-postgresfdw&lt;/a&gt;
&lt;a href="https://www.postgresql.fastware.com/postgresql-insider-fdw-ove" target="_blank" rel="noreferrer"&gt;https://www.postgresql.fastware.com/postgresql-insider-fdw-ove&lt;/a&gt;
&lt;a href="https://momjian.us/main/writings/pgsql/sharding.pdf" target="_blank" rel="noreferrer"&gt;https://momjian.us/main/writings/pgsql/sharding.pdf&lt;/a&gt;
&lt;a href="https://www.slideserve.com/johnna/sql-med-and-more-powerpoint-ppt-presentation" target="_blank" rel="noreferrer"&gt;https://www.slideserve.com/johnna/sql-med-and-more-powerpoint-ppt-presentation&lt;/a&gt;
&lt;a href="https://dbaplus.cn/news-19-2090-1.html" target="_blank" rel="noreferrer"&gt;https://dbaplus.cn/news-19-2090-1.html&lt;/a&gt;
&lt;a href="https://www.highgo.ca/2019/08/08/horizontal-scalability-with-sharding-in-postgresql-where-it-is-going-part-3-of-3/" target="_blank" rel="noreferrer"&gt;https://www.highgo.ca/2019/08/08/horizontal-scalability-with-sharding-in-postgresql-where-it-is-going-part-3-of-3/&lt;/a&gt;
&lt;a href="https://www.highgo.ca/2021/06/28/parallel-execution-of-postgres_fdw-scans-in-pg-14-important-step-forward-for-horizontal-scaling/" target="_blank" rel="noreferrer"&gt;https://www.highgo.ca/2021/06/28/parallel-execution-of-postgres_fdw-scans-in-pg-14-important-step-forward-for-horizontal-scaling/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL本地化</title><link>https://lastdba.com/2024/08/12/postgresql%E6%9C%AC%E5%9C%B0%E5%8C%96/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql%E6%9C%AC%E5%9C%B0%E5%8C%96/</guid><description>&lt;h2 class="relative group"&gt;本地化的概念
 &lt;div id="本地化的概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9c%ac%e5%9c%b0%e5%8c%96%e7%9a%84%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本地化的目的是支持不同国家、地区的语言特性、规则。比如拥有本地化支持后，可以使用支持汉语、法语、日语等等的字符集。除了字符集以外，还有字符排序规则和其他语言相关规则的支持，例如我们知道(&amp;lsquo;a&amp;rsquo;,&amp;lsquo;b&amp;rsquo;)该如何排序，那么(&amp;lsquo;a&amp;rsquo;,&amp;lsquo;A&amp;rsquo;)和(&amp;lsquo;啊&amp;rsquo;,&amp;lsquo;阿&amp;rsquo;)又该如何排序？
如果通过google去搜本地化、字符集、collation相关信息，可能会得到一些复杂又遥远的知识。最好的老师还是


&lt;img src="https://lastdba.com/img/csdn/4a8579e2070f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;本地化的概念
 &lt;div id="本地化的概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9c%ac%e5%9c%b0%e5%8c%96%e7%9a%84%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本地化的目的是支持不同国家、地区的语言特性、规则。比如拥有本地化支持后，可以使用支持汉语、法语、日语等等的字符集。除了字符集以外，还有字符排序规则和其他语言相关规则的支持，例如我们知道(&amp;lsquo;a&amp;rsquo;,&amp;lsquo;b&amp;rsquo;)该如何排序，那么(&amp;lsquo;a&amp;rsquo;,&amp;lsquo;A&amp;rsquo;)和(&amp;lsquo;啊&amp;rsquo;,&amp;lsquo;阿&amp;rsquo;)又该如何排序？
如果通过google去搜本地化、字符集、collation相关信息，可能会得到一些复杂又遥远的知识。最好的老师还是


&lt;img src="https://lastdba.com/img/csdn/4a8579e2070f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;本地化知识点总共分为3个部分：locale本地化支持、collation校验、字符集。&lt;/p&gt;

&lt;h2 class="relative group"&gt;locale
 &lt;div id="locale" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#locale" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg的本地化由由操作系统提供，需要检查操作系统是否支持&lt;code&gt;locale -a&lt;/code&gt;。在初始化数据库时可指定locale&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb --locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;也可以单独设置本地化子类：字符串排序、字符归类方法、数值格式、日期格式、时间格式、货币格式等&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb --locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;zh_CN --lc-monetary&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所有本地化子类：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;本地化子类&lt;/th&gt;
 &lt;th&gt;规则&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_COLLATE&lt;/td&gt;
 &lt;td&gt;String sort order&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_CTYPE&lt;/td&gt;
 &lt;td&gt;Character classification (What is a letter? Its upper-case equivalent?)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_MESSAGES&lt;/td&gt;
 &lt;td&gt;Language of messages&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_MONETARY&lt;/td&gt;
 &lt;td&gt;Formatting of currency amounts&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_NUMERIC&lt;/td&gt;
 &lt;td&gt;Formatting of numbers&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;LC_TIME&lt;/td&gt;
 &lt;td&gt;Formatting of dates and times&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些子类又可以分为两部分，其中lc_messages，lc_monetary，lc_numeric，lc_time在初始化后，可以通过参数进行调整。LC_COLLATE，LC_CTYPE属于collation，详见collation的调整。
locale设置会影响如下行为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sort order in queries using &lt;code&gt;ORDER BY&lt;/code&gt; or the standard comparison operators on textual data&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;upper&lt;/code&gt;, &lt;code&gt;lower&lt;/code&gt;, and &lt;code&gt;initcap&lt;/code&gt; functions&lt;/li&gt;
&lt;li&gt;Pattern matching operators (&lt;code&gt;LIKE&lt;/code&gt;, &lt;code&gt;SIMILAR TO&lt;/code&gt;, and POSIX-style regular expressions); locales affect both case insensitive matching and the classification of characters by character-class regular expressions&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;to_char&lt;/code&gt; family of functions&lt;/li&gt;
&lt;li&gt;The ability to use indexes with &lt;code&gt;LIKE&lt;/code&gt; clauses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;COLLATION
 &lt;div id="collation" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#collation" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;collation是字符排序的顺序和字符分类行为。一些数据库操作符依赖collation，比如order by、lower, upper、initcap 、to_char等等。
使用如下SQL查询系统表pg_collation，来获取字符集支持的LC_COLLATE和LC_CTYPE信息&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_encoding_to_char(collencoding) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt;,collname,collcollate,collctype &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; collname &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;C&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;POSIX&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;en_US.utf8&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.utf8&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;zh_SG.gb2312&amp;#39;&lt;/span&gt;) ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collctype 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+--------------+--------------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; POSIX &lt;span style="color:#f92672"&gt;|&lt;/span&gt; POSIX &lt;span style="color:#f92672"&gt;|&lt;/span&gt; POSIX
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EUC_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EUC_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_SG.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_SG.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_SG.gb2312&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;encoding是字符集，collname为collation的名字&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;encoding 为空时，表示这个 collation 支持所有的字符集&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;POSIX&lt;/code&gt;是所有平台都支持的collation，由&lt;code&gt;libc&lt;/code&gt;提供，其他collation取决于操作系统是否支持(&lt;code&gt;locale -a&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;default表示使用建库时的collation，可通过\l查看&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C&lt;/code&gt;语义上等价于&lt;code&gt;POSIX&lt;/code&gt;，但是PG仍然认为他们是不同的collation。他们的字符都以ASCII码对比，严格按照字节序比对大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;POSIX&amp;#34;&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;P21: &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt; mismatch &lt;span style="color:#66d9ef"&gt;between&lt;/span&gt; explicit collations &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;POSIX&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LINE &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;POSIX&amp;#34;&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: merge_collation_state, parse_collate.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;834&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;UTF8是最常见的字符集，我们最常见的语言环境是en_US和zh_CN&lt;/li&gt;
&lt;li&gt;可以通过&lt;code&gt;CREATE COLLATION ...&lt;/code&gt;创建自定义的collation。不过LC_COLLATE和LC_CTYPE不同的情况非常少见&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;LC_COLLATE
 &lt;div id="lc_collate" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lc_collate" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LC_COLLATE影响字符比对（排序、字符操作等等）
collate子句可以转化表达式的collation：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;expr &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意这里指定的是collation，不是lc_collate。如果没有显示指定collation，数据库默认使用字段的collation，如果字段没有指定collation，使用database的默认collation。&lt;/p&gt;
&lt;p&gt;不同的collation排序测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; l(col1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; l(col1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;), (&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; l(col1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这3个不同的collation有不同的lc_collate，排序方法应该是不一样的，从结果来看确实是不一样的，出现了3种排序结果。
&lt;strong&gt;collation C为什么A&amp;lt;a?&lt;/strong&gt;
collation C使用的ASCII的编码顺序，ASCII码中大写在小写前面。而en_US.utf8和zh_CN.utf8的英文字母明显不是这个顺序
&lt;strong&gt;中文的顺序&lt;/strong&gt;
同样是utf8字符集，中文环境和英文环境的中文顺序不一样。不同的lc_collate对于不同本地化语言，应该都可以对应到不同的alphabets。其中，lc_collate=C的排序一定是按字节序排的，虽然ASCII没有中文，但是C也可以排序中文，（基本）每个中文都可以对应UTF8的一个编码，而C以其字节序排序。&lt;/p&gt;

&lt;h3 class="relative group"&gt;LC_CTYPE
 &lt;div id="lc_ctype" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lc_ctype" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LC_CTYPE影响字符操作（如upper、initcap等）
如果字符串都是英文，比如是&amp;rsquo;abcD&amp;rsquo;，initcap在3种collation下都会转换为&amp;rsquo;Abcd&amp;rsquo;，这里不多展示了。
但是加入中文，结果就不一样了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; initcap(&lt;span style="color:#e6db74"&gt;&amp;#39;啊aAAa阿bBBb&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; initcap 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;Aaaa阿Bbbb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; initcap(&lt;span style="color:#e6db74"&gt;&amp;#39;啊aAAa阿aAAa&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; initcap 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;aaaa阿aaaa
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; initcap(&lt;span style="color:#e6db74"&gt;&amp;#39;啊aAAa阿aAAa&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; initcap 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;啊&lt;/span&gt;aaaa阿aaaa&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;LC_CTYPE=C时，initcap把每个非连续英文字符串的首字母大写，而en_US.utf8和zh_CN.utf8只会将首个字符大写（中文就不会变），其他英文字符小写。
initcap中文也许处于需求不明的状况，但是我们可以得出结论：&lt;strong&gt;不同的LC_CTYPE会导致initcap等字符敏感函数结果不一样&lt;/strong&gt;。
另外，中文对于大小写不敏感，一些其他本地化语言同样有大小写，不同的LC_CTYPE导致的结果会更复杂。&lt;/p&gt;

&lt;h2 class="relative group"&gt;字符集
 &lt;div id="字符集" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%97%e7%ac%a6%e9%9b%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;字符集基础
 &lt;div id="字符集基础" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%97%e7%ac%a6%e9%9b%86%e5%9f%ba%e7%a1%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PostgreSQL支持不同的字符集character sets（也叫encodings）。字符集于collation是两个概念，但是字符集必须跟LC_CTYPE，LC_COLLATE兼容。就像在pg_collation中看到的那样，C/POSIX支持所有字符集，而其他collation只支持一种字符集（linux系统中）。&lt;/p&gt;
&lt;p&gt;PostgreSQL中文相关可用的字符集：
&lt;em&gt;(*collation C由libc库提供，部分collation可以由ICU库提供，需提前编译)&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Name&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Language&lt;/th&gt;
 &lt;th&gt;Server端是否支持?&lt;/th&gt;
 &lt;th&gt;ICU是否支持?&lt;/th&gt;
 &lt;th&gt;Bytes/Char&lt;/th&gt;
 &lt;th&gt;Aliases&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;BIG5&lt;/td&gt;
 &lt;td&gt;Big Five&lt;/td&gt;
 &lt;td&gt;繁体中文&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;1–2&lt;/td&gt;
 &lt;td&gt;WIN950, Windows950&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;EUC_CN&lt;/td&gt;
 &lt;td&gt;Extended UNIX Code-CN&lt;/td&gt;
 &lt;td&gt;简体中文&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;1–3&lt;/td&gt;
 &lt;td&gt;GB2312&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GB18030&lt;/td&gt;
 &lt;td&gt;National Standard&lt;/td&gt;
 &lt;td&gt;中文&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;1–4&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GBK&lt;/td&gt;
 &lt;td&gt;Extended National Standard&lt;/td&gt;
 &lt;td&gt;简体中文&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;1–2&lt;/td&gt;
 &lt;td&gt;WIN936, Windows936&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;td&gt;Unicode, 8-bit&lt;/td&gt;
 &lt;td&gt;all&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;1–4&lt;/td&gt;
 &lt;td&gt;Unicode&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;繁体中文&lt;/strong&gt;：
&lt;a href="https://baike.baidu.com/item/%E5%A4%A7%E4%BA%94%E7%A0%81/2413431?fr=ge_ala" target="_blank" rel="noreferrer"&gt;BIG5&lt;/a&gt;是最常见的繁体中文字符集标准。之前是业界标准，后来被录入为国家标准。
&lt;strong&gt;简体中文&lt;/strong&gt;：
GB是国标的意思，GB2312、GB18030、GBK都是我国的国家字符集标准。由于生僻字等问题，并经过多年发展产生了一些历史版本，所以标准看上去有多个。
其中&lt;a href="https://baike.baidu.com/item/EUC-CN/4514294?fr=ge_ala" target="_blank" rel="noreferrer"&gt;EUC_CN&lt;/a&gt;全称为 Extended UNIX Code-CN ，其实就是&lt;a href="https://baike.baidu.com/item/%E4%BF%A1%E6%81%AF%E4%BA%A4%E6%8D%A2%E7%94%A8%E6%B1%89%E5%AD%97%E7%BC%96%E7%A0%81%E5%AD%97%E7%AC%A6%E9%9B%86/8074272?fromModule=lemma_inlink&amp;amp;fromtitle=GB2312&amp;amp;fromid=483170" target="_blank" rel="noreferrer"&gt;GB2312&lt;/a&gt;，但它也不能处理所有罕见字。类似命名的还有EUC_KR,EUC_JP,EUC_TW等等。
&lt;strong&gt;国际标准&lt;/strong&gt;：
上面的字符集都是国家标准，他们除了支持英、中外不支持其他语言。而国际标准支持世界上所有语言，这就是&lt;a href="https://home.unicode.org/" target="_blank" rel="noreferrer"&gt;unicode&lt;/a&gt;国际编码标准(甚至emoji也包含其中 &amp;#x1f44d;)。（还有个著名的国际标准组织ISO也在维护字符集，他俩有交集，这里先忽略ISO）。
由于Unicode编码方案的不同又有UTF-8、UTF-16、UTF-32三种编码方式。&lt;/p&gt;
&lt;p&gt;UTF-8编码格式:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字节&lt;/th&gt;
 &lt;th&gt;格式&lt;/th&gt;
 &lt;th&gt;实际编码位&lt;/th&gt;
 &lt;th&gt;码点范围&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1字节&lt;/td&gt;
 &lt;td&gt;0xxxxxxx&lt;/td&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;0 ~ 127&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2字节&lt;/td&gt;
 &lt;td&gt;110xxxxx 10xxxxxx&lt;/td&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;128 ~ 2047&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3字节&lt;/td&gt;
 &lt;td&gt;1110xxxx 10xxxxxx 10xxxxxx&lt;/td&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td&gt;2048 ~ 65535&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4字节&lt;/td&gt;
 &lt;td&gt;11110xxx 10xxxxxx 10xxxxxx 10xxxxxx&lt;/td&gt;
 &lt;td&gt;21&lt;/td&gt;
 &lt;td&gt;65536 ~ 2097151&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;UTF8编码是变长的。
0x00-0x7F之间的字符(1字节），UTF-8编码与ASCII（American Standard Code for Information Interchange 美国标准信息交换代码）编码完全相同，所以UTF-8是完全兼容ASCII的。
由于同源、同义、相似性，在unicode中中日韩越使用了同一编码，称为&lt;a href="https://baike.baidu.com/item/%E4%B8%AD%E6%97%A5%E9%9F%A9%E8%B6%8A%E7%BB%9F%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97/1301611?fromModule=lemma_inlink" target="_blank" rel="noreferrer"&gt;中日韩统一表意文字（或称中日韩越统一表意文字）&lt;/a&gt;。
中日韩统一表意文字编码范围为：3400-4DBF/4E00-9FFF/20000-3FFFF



&lt;img src="https://lastdba.com/img/csdn/f914ea2ca52f.png" alt="" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;字符集转换
 &lt;div id="字符集转换" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%97%e7%ac%a6%e9%9b%86%e8%bd%ac%e6%8d%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;server_encoding与client_encoding不一致，可发生自动转换Server查出来的字符集。设置服务端字和客户端字符集参考设置字符集一节。
中文相关字符集Server/Client可转化表：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Server Character Set&lt;/th&gt;
 &lt;th&gt;Available Client Character Sets&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;BIG5&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;not supported as a server encoding&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;EUC_CN（GB2312）&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;&lt;em&gt;EUC_CN&lt;/em&gt;（GB2312）, &lt;code&gt;MULE_INTERNAL&lt;/code&gt;, &lt;code&gt;UTF8&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GB18030&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;not supported as a server encoding&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GBK&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;not supported as a server encoding&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;UTF8&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;&lt;em&gt;all supported encodings&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GB18030，GBK服务端都不支持，所以其实只有EUC_CN（GB2312）、UTF8能在Server/Client转换。&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以上是可以转换的字符集，仍需要CONVERSATION的支持。PG内置了一些转换函数，可通过&lt;code&gt;pg_conversion&lt;/code&gt;查看：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Conversion Name&lt;/th&gt;
 &lt;th&gt;Source Encoding&lt;/th&gt;
 &lt;th&gt;Destination Encoding&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;big5_to_utf8&lt;/td&gt;
 &lt;td&gt;BIG5&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;euc_cn_to_utf8&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;EUC_CN&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;UTF8&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;gb18030_to_utf8&lt;/td&gt;
 &lt;td&gt;GB18030&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;gbk_to_utf8&lt;/td&gt;
 &lt;td&gt;GBK&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;utf8_to_big5&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;td&gt;BIG5&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;utf8_to_euc_cn&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;UTF8&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;EUC_CN&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;utf8_to_gb18030&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;td&gt;GB18030&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;utf8_to_gbk&lt;/td&gt;
 &lt;td&gt;UTF8&lt;/td&gt;
 &lt;td&gt;GBK&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可通过&lt;code&gt;create conversation&lt;/code&gt;语句创建自定义的转换，需指定转换的function。
有些字符集间看上去可以转换，但是server端根本不支持存储这些字符集（如big5、gb18030、gbk），所以也没啥用。我们这里仅需要知道euc_cn和utf8能相互转换就可以了。
没有CONVERSATION是不能发生转换的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--EUC_CN的database
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; EUC_KR
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EUC_KR: invalid &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;conversion&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;procedure&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;found&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;字符集转换测试&lt;/strong&gt;：
&lt;em&gt;需要注意客户端的字符集设置（如CRT的 &amp;ldquo;session&amp;rdquo;-&amp;ldquo;Appearance&amp;rdquo;-&amp;ldquo;Character encoding&amp;rdquo;）&lt;/em&gt;
&lt;em&gt;至少&lt;/em&gt;有3个端有字符集的概念：数据库server、数据库client、UI客户端。CONVERSATION也只能控制：数据库server -&amp;gt; 数据库client
1.server为UTF8的转换测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; zh(col1 varchar(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--〇 ling是一个中文
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--CRT不设置为UTF8中文全是乱码，只有CRT设置UTF8来插入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; server_encoding;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_encoding 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; client_encoding;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client_encoding 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--完全没有转换的情况下，UTF8正常展示。此时3端字符集为：UTF8 - UTF8 - UTF8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;〇&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--切换数据库client字符集，此时3端字符集为：UTF8 - EUC_CN - UTF8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; EUC_CN; &lt;span style="color:#75715e"&gt;--设置客户端字符集
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22021&lt;/span&gt;: invalid byte sequence &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xe9 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x98
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: report_invalid_encoding, mbutils.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1597&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22021&lt;/span&gt;: invalid byte sequence &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xe3 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x80
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22021&lt;/span&gt;: invalid byte sequence &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xe3 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x80
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--“阿”和“〇”看上去不能转换为EUC_CN，但不是这样的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;limit&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;B0&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;A2&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--第二行即是&amp;#34;阿&amp;#34;，数据库server/client看上去转换了字符集，从UTF8转换为了EUC_CN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--但是可能是因为UI客户端问题没有正确显示（此时UI客户端CRT为UTF8）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--然而把CRT改成GB2312还是不会正确展示
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;limit&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;B0&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;A2&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--当查询〇时，数据库直接抛出报错，说明〇不能从UTF8转换为EUC_CN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; zh ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;P05: character &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; byte sequence &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xe3 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x80 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x87 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UTF8&amp;#34;&lt;/span&gt; has &lt;span style="color:#66d9ef"&gt;no&lt;/span&gt; equivalent &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: report_untranslatable_char, mbutils.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1631&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.server为EUC_CN的转换测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; server_encoding; &lt;span style="color:#75715e"&gt;--database为EUC_CN字符集
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_encoding 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EUC_CN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--在EUC_CN库下同样创建一个zh表，此时尝试插入就有问题了 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; zh &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;P05: character &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; byte sequence &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xe3 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x80 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x87 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UTF8&amp;#34;&lt;/span&gt; has &lt;span style="color:#66d9ef"&gt;no&lt;/span&gt; equivalent &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: report_untranslatable_char, mbutils.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1631&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;同样报错〇不能从UTF8转换为EUC_CN。EUC_CN（GB2312）中文编码不完全与UTF8相同，EUC_CN（GB2312）不是所有中文都包含的，特别是罕见字。&lt;/p&gt;

&lt;h2 class="relative group"&gt;设置locale、collation和字符集
 &lt;div id="设置localecollation和字符集" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%ae%be%e7%bd%aelocalecollation%e5%92%8c%e5%ad%97%e7%ac%a6%e9%9b%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;上面已经了解过本地化和字符集设置了，这里做一个汇总&lt;/p&gt;

&lt;h3 class="relative group"&gt;database cluster的locale、collation、字符集
 &lt;div id="database-cluster的localecollation字符集" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#database-cluster%e7%9a%84localecollation%e5%ad%97%e7%ac%a6%e9%9b%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;初始化时可设置database cluster的locale和字符集，参考：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb -D $DATADIR -E UTF8 --locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb -D $DATADIR -E UTF8 --locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 --lc_collate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C --lc_ctype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb -D $DATADIR -E UTF8 --locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 --lc_collate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C --lc_ctype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C --lc-messages&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 --lc-monetary&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 --lc-numeric&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8 --lc-time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;en_US.UTF8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;initdb&lt;/code&gt;会创建postgres，template1，和template0三个库。&lt;code&gt;create database&lt;/code&gt;语句时默认使用template1创建库。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;encoding设置字符集；locale设置LC_COLLATE，LC_CTYPE，LC_MESSAGES，LC_MONETARY，LC_NUMERIC，LC_TIME，除非特别指定（如&amp;ndash;lc_collate）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LC_COLLATE，LC_CTYPE称为collation，还可在database、列、索引上设置。LC_MESSAGES，LC_MONETARY，LC_NUMERIC，LC_TIME为实例参数，可随时修改。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;encoding只能在初始化、创建database时设置，一旦设置不可修改。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;database的collation、字符集
 &lt;div id="database的collation字符集" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#database%e7%9a%84collation%e5%ad%97%e7%ac%a6%e9%9b%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;创建database时可设置database的字符集、lc_collate、lc_ctype。&lt;/p&gt;
&lt;p&gt;create database ,createdb都可以在创建database时指定字符集，一旦创建就不能修改database的字符集。两个命令都是使用template库来创建database&lt;/p&gt;
&lt;p&gt;template又有template0和template1，官方文档有这样一句话：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Another common reason for copying &lt;code&gt;template0&lt;/code&gt; instead of &lt;code&gt;template1&lt;/code&gt; is that new encoding and locale settings can be specified when copying &lt;code&gt;template0&lt;/code&gt;, whereas a copy of &lt;code&gt;template1&lt;/code&gt; must use the same settings it does. This is because &lt;code&gt;template1&lt;/code&gt; might contain encoding-specific or locale-specific data, while &lt;code&gt;template0&lt;/code&gt; is known not to.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;template1是可写数据的模板库，可能包含本地化过的数据，而template0不能写数据，所以要创建不同的本地化库应使用template0。&lt;/p&gt;
&lt;p&gt;而且要显示使用template0，因为不指定的话默认是template1。所以在创建database时没有指定template1且指定其他字符集会报错：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; db_GB2312 &lt;span style="color:#66d9ef"&gt;ENCODING&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;EUC_CN&amp;#39;&lt;/span&gt; LC_COLLATE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt; LC_CTYPE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22023&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; (EUC_CN) &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; incompatible &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; (UTF8)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Use the same &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; use template0 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;另外，不能在创建database时通过指定locale来设置字符集&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; db_GB2312 locale &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;template0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;22023&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UTF8&amp;#34;&lt;/span&gt; does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; locale &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.gb2312&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: The chosen LC_CTYPE setting requires &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;EUC_CN&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: check_encoding_locale_matches, dbcommands.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;773&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;报错表示需要指定LC_CYTPE子选项，把collation相关子选项全部加上仍然报错：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; db_GB2312 LOCALE &lt;span style="color:#e6db74"&gt;&amp;#39;EUC_CN&amp;#39;&lt;/span&gt; LC_COLLATE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt; LC_CTYPE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42601&lt;/span&gt;: conflicting &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; redundant &lt;span style="color:#66d9ef"&gt;options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: LOCALE cannot be specified together &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; LC_COLLATE &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; LC_CTYPE.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;LOCALE又不能跟LC_CTYPE等子选项一起使用
然后把locale去掉，通过设置字符集、LC_COLLATE、LC_CTYPE 来设置，可以成功。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;创建指定字符集的database的正确姿势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create database&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; db_GB2312 &lt;span style="color:#66d9ef"&gt;ENCODING&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;EUC_CN&amp;#39;&lt;/span&gt; LC_COLLATE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt; LC_CTYPE &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN.gb2312&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;template0&amp;#39;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;createdb
通过cli命令createdb来创建，createdb封装了create database，他俩是等价的：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; createdb -E EUC_CN -T template0 --lc-collate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;zh_CN.gb2312 --lc-ctype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;zh_CN.gb2312 db_GB2312&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;查看database字符集：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pg_database&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; datname,pg_encoding_to_char(&lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt;),datcollate,datctype,datlocprovider,daticulocale &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_database;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;show参数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;SERVER_ENCODING&lt;/code&gt;,&lt;code&gt;LC_COLLATE&lt;/code&gt;,&lt;code&gt;LC_CTYPE&lt;/code&gt;三个参数都是不可更改的，分别展示&lt;em&gt;当前&lt;/em&gt;database的server端字符集、LC_COLLATE、LC_CTYPE&lt;/p&gt;

&lt;h3 class="relative group"&gt;列的collation
 &lt;div id="列的collation" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%97%e7%9a%84collation" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;collation只跟字符排序、字符函数相关，跟编码不相关。在没有索引的情况下，修改列的collation相当于只是在调整这个列的default排序输出，有索引的情况下会重建索引。不指定列的collation默认与database一致。&lt;/p&gt;
&lt;p&gt;建表时指定collation：（注意有些字段类型是un-collatable的，比如int）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; t1(col1 varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; t1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; col1 &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;注意：alter table不修改长度是不会重建表的，但是一定会重建索引&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查看列的默认collation&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;. &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; t1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;. information_schema.columns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; table_catalog,table_schema,&lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;column_name&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;collation_name&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.columns &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;t1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;. pg_attribute
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; a.attrelid::regclass,a.attname,a.attcollation,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collname,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collcollate,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collctype &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_attribute a &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; a.attcollation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a.attrelid::regclass&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; a.attcollation&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;推荐方式3查看。\d+ ,information_schema.columns虽然能看到collname，但是collname不是唯一的。只有方式3可以看到collate,ctype&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;指定collate和查看pg_attribute的测试：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tlzl(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) ,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col2 varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col3 varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col4 varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;--列的collation相当于给列打上默认排序的标记，也看不到具体是哪个collate和ctype
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.tlzl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Compression &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------+------------+----------+---------+----------+-------------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--collname和collate，ctype不是一一对应的，上面的col3 zh_CN看不出来collate是哪个
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_encoding_to_char(collencoding) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt;,collname,collcollate,collctype &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; collname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zh_CN%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collctype 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+--------------+--------------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EUC_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EUC_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.gb2312
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UTF8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--pg_attribute展示比\d+准确
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; a.attrelid::regclass,a.attname,a.attcollation,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collname,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collcollate,&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.collctype &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_attribute a &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; a.attcollation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a.attrelid::regclass&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; a.attcollation&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attrelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; attname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; attcollation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collctype 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+--------------+------------+-------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; col1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; col2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;950&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; col4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12562&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; col3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13200&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN.utf8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时才知道，col3 zh_CN的collate是zh_CN.utf8 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;修改列的collate重写测试：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--给字段加索引，看看重写情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxcol4 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl(col4);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;) TableRelid, pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idxcol4&amp;#39;&lt;/span&gt;) IndexRelid; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablerelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------+------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41006&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41015&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; col4 &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;) TableRelid, pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idxcol4&amp;#39;&lt;/span&gt;) IndexRelid; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablerelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------+------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41006&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41016&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--表没有重写，索引重写了&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;列的collation只是标记，修改列的collation不会重写表，但是如果其上有索引，那么会重写这个索引（有时候不会见下面一节）。&lt;/p&gt;

&lt;h3 class="relative group"&gt;索引的collation
 &lt;div id="索引的collation" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%b4%a2%e5%bc%95%e7%9a%84collation" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在创建索引时，如不显示指定索引的collation，那么索引会使用列上声明的collation。&lt;/p&gt;
&lt;p&gt;创建索引时显示使用collation：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_C &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl(col3 &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;另外，索引还可以以text_pattern_ops，varchar_pattern_ops，bpchar_pattern_ops来创建，此时的索引不依赖collation的规则，而是一个字符一个字符的对比&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The difference from the default operator classes is that the values are compared strictly character by character rather than according to the locale-specific collation rules.&lt;/p&gt;
&lt;/blockquote&gt;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; test_index &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; test_table (col varchar_pattern_ops);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其实这种索引跟collation不是完全无关，索引一定有一个排序规则，这种索引的排序规则看上去跟C一致。参考like不走索引一节&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查看索引的collation:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#75715e"&gt;--\d+会展示指定过collate的索引，如果没有的话使用的是列默认索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; tlzl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.tlzl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Compression &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------+------------+----------+---------+----------+-------------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; zh_CN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; en_US.utf8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_c&amp;#34;&lt;/span&gt; btree (col3 &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idxcol4&amp;#34;&lt;/span&gt; btree (col4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过pg_index查看更为清晰:（pg_index的indcollation类型是oidvector的，不能直接转化为oid，查起来麻烦点）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; indcollation,indexrelid::regclass &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_index &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; indexrelid::regclass &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idx_C&amp;#39;&lt;/span&gt;::regclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; indcollation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;950&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; idx_c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; oid,pg_encoding_to_char(collencoding) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt;,collname,collcollate,collctype &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_collation &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; oid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;950&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collcollate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; collctype 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----+----------+----------+-------------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;950&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;另外，不能通过alter index改变索引的collation，只能删除重建&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;测试：指定过索引collate后，修改列的collate是否会重写索引？&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;) TableRelid, pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idxcol4&amp;#39;&lt;/span&gt;) IndexRelid4,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idx_c&amp;#39;&lt;/span&gt;) IndexRelidC; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablerelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelid4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelidc 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------+------------------+------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41020&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41023&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41024&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; col3 &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;tlzl&amp;#39;&lt;/span&gt;) TableRelid, pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idxcol4&amp;#39;&lt;/span&gt;) IndexRelid4,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idx_c&amp;#39;&lt;/span&gt;) IndexRelidC; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablerelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelid4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; indexrelidc 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------+------------------+------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41020&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41023&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40996&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;41024&lt;/span&gt; &lt;span style="color:#75715e"&gt;--idx_c的relfileid没有变&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果指定过索引的collate，修改其字段默认collate，不会重新索引。&lt;/p&gt;

&lt;h3 class="relative group"&gt;客户端的字符集
 &lt;div id="客户端的字符集" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e5%ad%97%e7%ac%a6%e9%9b%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;客户端设置与database不同的字符集，会发生字符集转换，也可能转换不成功，具体参考字符集转换一节。&lt;/p&gt;
&lt;p&gt;服务端的字符集在创建database后无法改变，client的字符集可随时调整。&lt;/p&gt;
&lt;p&gt;Client字符集设置方法很多：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接在客户端设置&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; UTF8 &lt;span style="color:#75715e"&gt;--仅psql支持
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; CLIENT_ENCODING &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; UTF8; &lt;span style="color:#75715e"&gt;--session级修改参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NAMES&lt;/span&gt; UTF8; &lt;span style="color:#75715e"&gt;--sql标准&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;设置环境变量PGCLIENTENCODING&lt;/li&gt;
&lt;li&gt;设置client_encoding服务端配置参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;优先级：客户端设置&amp;gt;环境变量PGCLIENTENCODING&amp;gt;client_encoding服务端配置参数&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查看client字符集：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;encoding&lt;/span&gt; &lt;span style="color:#75715e"&gt;--仅psql支持
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SHOW&lt;/span&gt; client_encoding;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;表达式collate
 &lt;div id="表达式collate" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%a1%a8%e8%be%be%e5%bc%8fcollate" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;表达式加collate会覆盖表达式原本的collation，相当于指定了排序collation。&lt;/p&gt;
&lt;p&gt;需在表达式的最后加collate关键字：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;expr &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;collation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--例如
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tab1 &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;COLLATE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;排序和collate索引选择详见排序结果问题一节。&lt;/p&gt;

&lt;h2 class="relative group"&gt;MORE
 &lt;div id="more" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#more" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;概念整理
 &lt;div id="概念整理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%a6%82%e5%bf%b5%e6%95%b4%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PostgreSQL本地化有三个重要概念：字符集、locale、collation，需要弄清他们的关系。&lt;/p&gt;
&lt;p&gt;字符集在服务端的设置非常重要，只能在初始化和建db时指定，建库后不可修改。字符集选择直接影响编码方式，collation并不是，但是他俩之间有依赖关系。locale同样可以在初始化时指定，其中collation可在建库时指定，也可以单独指定列的collation，注意他们只是默认值。只有在建索引时指定collation，会影响其真正的存储顺序。不同的collation是无法使用索引的，即使他们同源。&lt;/p&gt;
&lt;p&gt;client字符集和LC_MASSAGES等4个参数都比较简单，可直接修改参数，与数据存储无关。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6c422851b81d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;排序结果问题
 &lt;div id="排序结果问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%8e%92%e5%ba%8f%e7%bb%93%e6%9e%9c%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为utf8是最常见的字符集，我们测试utf相关的collation排序&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; db_UTF8 &lt;span style="color:#66d9ef"&gt;ENCODING&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;UTF8&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;template&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;template0&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--建一个UTF8的库，collation无所谓
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;use db_UTF8;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tzlz(name varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;),(&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不同collation的order by结果：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zh_CN.utf8&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;顺序&lt;/th&gt;
 &lt;th&gt;default&lt;/th&gt;
 &lt;th&gt;C&lt;/th&gt;
 &lt;th&gt;en_US&lt;/th&gt;
 &lt;th&gt;en_US.utf8&lt;/th&gt;
 &lt;th&gt;zh_CN&lt;/th&gt;
 &lt;th&gt;zh_CN.utf8&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;td&gt;a&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;td&gt;A&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;td&gt;aa&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;td&gt;AA&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;td&gt;啊&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;td&gt;阿&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;td&gt;〇&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;这里的default是en_US.utf8（字段collation(default)-&amp;gt;database collation(en_US.utf8)）&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x1f31f; &lt;strong&gt;C、en_US.uft8、zh_CN.uft8排序结果都不同&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;collate和索引扫描测试：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxzlz_default &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz(name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxzlz_C &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz(name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxzlz_enUS_utf8 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz(name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;使用collate在索引上的优化：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--不加任何collate关键字，简单的索引扫描，不会额外排序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8_c&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_default &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--谓词加collate转换，可以走到正确的索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_c &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_enus_utf8 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--但是collation的名字必须一致
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;232&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--同时order by也需要加collate转换表达式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时使用了正确的索引，但是order by的时候判断为不同的collation（哪怕他们是一样的）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_enus_utf8 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--where和order by都加上collate转换，可以小选择正确的索引，且不会在发生排序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;AA&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;啊&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;〇&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_enus_utf8 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ANY&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;{a,aa,A,AA,啊,阿,〇}&amp;#39;&lt;/span&gt;::text[]))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;索引在指定collation后，sql需要显示使用collate关键字转换表达式，即便default与当前collation一致，pg也不会使用到索引。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;like不走索引
 &lt;div id="like不走索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#like%e4%b8%8d%e8%b5%b0%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;The drawback of using locales other than &lt;code&gt;C&lt;/code&gt; or &lt;code&gt;POSIX&lt;/code&gt; in PostgreSQL is its performance impact. It slows character handling and prevents ordinary indexes from being used by &lt;code&gt;LIKE&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;PostgreSQL原话：使用非C or POSIX会阻止使用普通索引！&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_c &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (name &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;~~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a%&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_c &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (name &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;~~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a%&amp;#39;&lt;/span&gt;::text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;PostgreSQL在索引扫描时把like转化为了&amp;gt;=和&amp;lt;，&amp;lt;还加了一个比输入的值大一号的值，这里就有问题了，collation跟排序强相关，ASCII码中a+1是b，但是汉字又如何？&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxzlz_c &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (name &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;陿&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;~~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;::text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;果然出现了另一个汉字！&lt;/p&gt;
&lt;p&gt;如果是全表扫描，不会出现&amp;gt;= &amp;lt;的情况&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxzlz_c;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DROP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;en_US.utf8&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;170&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;~~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;::text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以创建一个与collation规则无关的索引（pg官方声称无关）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_pattern &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; tzlz (name varchar_pattern_ops);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;来看看他的执行计划&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_utf8&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tzlz &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_pattern &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name &lt;span style="color:#f92672"&gt;~&amp;gt;=~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (name &lt;span style="color:#f92672"&gt;~&amp;lt;~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;陿&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((name)::text &lt;span style="color:#f92672"&gt;~~&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;阿%&amp;#39;&lt;/span&gt;::text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;他还是把大1号的字符串自己生成了，这跟collation一定是有关系的···，看上去就是C&lt;/p&gt;
&lt;p&gt;所以可以得出结论：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg在like使用普通索引时，需要把其转换为&amp;gt;= &amp;lt;，此时必须出现一个比当前字符串大1的值。而collation又与大小强相关，此时只能使用同一collation索引才能保证数据正确。pg选择了非本地化的collation C。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;临时解决这个问题最快的办法是新建一个collation C或pattern索引:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxzlz_C &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tzlz(name &lt;span style="color:#66d9ef"&gt;collate&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_pattern &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; tzlz (name varchar_pattern_ops);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其他调整各级别的默认collation参考上面的章节。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;开发习惯在建索引时不会指定collation，如果不是C或pattern，都走不了like，在加上要选择国际字符集utf8，这样在数据库运维时选择的本地化方式就非常少了。字符集为utf8，collation为C&lt;/em&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;参考
 &lt;div id="参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://dbafix.com/what-is-the-impact-of-lc_ctype-on-a-postgresql-database/#:~:text=Having%20LC_CTYPE%20set%20to%20%E2%80%98C%E2%80%99%20implies%20that%20C,Postgres%20on%20top%20of%20these%20libc%20functions%2C%20they%E2%80%99re" target="_blank" rel="noreferrer"&gt;https://dbafix.com/what-is-the-impact-of-lc_ctype-on-a-postgresql-database/#:~:text=Having%20LC_CTYPE%20set%20to%20%E2%80%98C%E2%80%99%20implies%20that%20C,Postgres%20on%20top%20of%20these%20libc%20functions%2C%20they%E2%80%99re&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/charset.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/charset.html&lt;/a&gt;
&lt;a href="https://www.bookstack.cn/read/rds-best-pratice/bfc0037fe00d87dc.md" target="_blank" rel="noreferrer"&gt;https://www.bookstack.cn/read/rds-best-pratice/bfc0037fe00d87dc.md&lt;/a&gt;
&lt;a href="https://help.aliyun.com/zh/rds/apsaradb-rds-for-postgresql/configure-the-collation-of-a-database-on-an-apsaradb-rds-for-postgresql-instance" target="_blank" rel="noreferrer"&gt;https://help.aliyun.com/zh/rds/apsaradb-rds-for-postgresql/configure-the-collation-of-a-database-on-an-apsaradb-rds-for-postgresql-instance&lt;/a&gt;
&lt;a href="https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E7%A0%81/2985798?fromModule=lemma_inlink&amp;amp;fromtitle=Unicode&amp;amp;fromid=750500" target="_blank" rel="noreferrer"&gt;https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E7%A0%81/2985798?fromModule=lemma_inlink&amp;fromtitle=Unicode&amp;fromid=750500&lt;/a&gt;
&lt;a href="https://baike.baidu.com/item/%E4%B8%AD%E6%97%A5%E9%9F%A9%E8%B6%8A%E7%BB%9F%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97/1301611?fromModule=lemma_inlink" target="_blank" rel="noreferrer"&gt;https://baike.baidu.com/item/%E4%B8%AD%E6%97%A5%E9%9F%A9%E8%B6%8A%E7%BB%9F%E4%B8%80%E8%A1%A8%E6%84%8F%E6%96%87%E5%AD%97/1301611?fromModule=lemma_inlink&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/songyundong1993/article/details/128739919" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/songyundong1993/article/details/128739919&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL分区表</title><link>https://lastdba.com/2024/08/12/postgresql%E5%88%86%E5%8C%BA%E8%A1%A8/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql%E5%88%86%E5%8C%BA%E8%A1%A8/</guid><description>&lt;h2 class="relative group"&gt;什么是分区表
 &lt;div id="什么是分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/787a5ce076e9.png" alt="Postgres Table Partitioning" /&gt;
数据库分区表将表数据分成更小的物理分片，以此提高性能、可用性、易管理性。分区表是关系型数据库中比较常见的对大表的优化方式，数据库管理系统一般都提供了分区管理，而业务可以直接访问分区表而不需要调整业务架构，当然好的性能需要合理的分区访问方式。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;什么是分区表
 &lt;div id="什么是分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/787a5ce076e9.png" alt="Postgres Table Partitioning" /&gt;
数据库分区表将表数据分成更小的物理分片，以此提高性能、可用性、易管理性。分区表是关系型数据库中比较常见的对大表的优化方式，数据库管理系统一般都提供了分区管理，而业务可以直接访问分区表而不需要调整业务架构，当然好的性能需要合理的分区访问方式。&lt;/p&gt;
&lt;p&gt;分区表是数据库中常见的技术，而PostgreSQL中的分区表有许多专有的特性，比如分区表实现方案多、分区为普通表、分区维护方案、SQL优化还有一些分区表的问题。&lt;/p&gt;

&lt;h2 class="relative group"&gt;分区表的实现
 &lt;div id="分区表的实现" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e5%ae%9e%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PostgreSQL数据库有各式各样的分区实现方式。官方支持的有声明式分区和继承式分区，而三方插件包括pathman、partman等等。在官方声明式分区实现后，基本只推荐一种分区方式：声明式分区。由于再拓展不同实现的分区表的功能、细节、历史等差别会使篇幅过长，且未来意义不大，本篇主要讨论的是声明式分区，其他方式实现的分区功能只会简单介绍。但是由于历史存量和一些功能差异，了解声明分区、继承分区、pathman还是有必要的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;声明分区表
 &lt;div id="声明分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a3%b0%e6%98%8e%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;声明分区也叫原生分区，从PG10版本开始支持，相当于“官方支持”的分区表，也是最为推荐的分区方式。虽然与继承分区不一样，但是其内部也是用继承表实现的。声明分区只支持3种分区方式：range分区、list分区、hash分区&lt;/p&gt;

&lt;h4 class="relative group"&gt;range分区
 &lt;div id="range分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#range%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f252d7be9e4d.png" alt="" /&gt;
range分区表以范围进行分区，分区边界为[t1,t2)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PUBLIC&lt;/span&gt;.LZLPARTITION1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id int,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name varchar(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DATE_CREATED &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; now()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) PARTITION &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; RANGE(DATE_CREATED);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.lzlpartition1 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;(id,DATE_CREATED)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION1_202301 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION1_202302 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--往分区表添加一些数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; random() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;, md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text),&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; generate_series(&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;::date, &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-28&amp;#39;&lt;/span&gt;::date, &lt;span style="color:#e6db74"&gt;&amp;#39;1 minute&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;83521&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;range分区的from t1 to t2，为[t1,t2)范围，下边界包含上边界不包含。&lt;/p&gt;
&lt;p&gt;查看分区表，每个分区也是单独的表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Compression &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+-------------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: RANGE (date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id, date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzlpartition1_202302 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1_202301&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Compression &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+-------------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: lzlpartition1 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_202301_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id, date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;分区上的主键、索引、字段null/CHECK约束自动创建。由于分区也是独立的表，约束和索引也可以单独在分区上创建。（attach则不会自动创建这些，详见attach一节）&lt;/p&gt;

&lt;h4 class="relative group"&gt;list分区
 &lt;div id="list分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#list%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e3d094556a5d.png" alt="" /&gt;
list分区以指定的分区值将数据存放到对应的分区上&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; cities (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; city_id bigserial &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name text,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; population bigint
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) PARTITION &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; LIST (&lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;lower&lt;/span&gt;(name), &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; cities_ab
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; cities &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; cities_null
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; cities (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINT&lt;/span&gt; city_id_nonzero &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (city_id &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; cities(name,population) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Acity&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; cities(name,population) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; cities;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; city_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; population 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+---------+--------+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cities_ab &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Acity &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cities_null &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;list分区表可以创建null分区&lt;/p&gt;

&lt;h4 class="relative group"&gt;hash分区
 &lt;div id="hash分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hash%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9e18df7edc15.png" alt="" /&gt;
hash分区将数据散列存储在各个分区上，以打散热点数据&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders (order_id int,name varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)) PARTITION &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; HASH (order_id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p1 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p2 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p3 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不能创建默认分区，也不能创建超过MODULUS的分区&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p2 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;P16: remainder &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; hash partition must be &lt;span style="color:#66d9ef"&gt;less&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;than&lt;/span&gt; modulus
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: transformPartitionBound, parse_utilcmd.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3939&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p4 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;P16: a hash&lt;span style="color:#f92672"&gt;-&lt;/span&gt;partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; may &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; have a &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; partition
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: transformPartitionBound, parse_utilcmd.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3909&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;插入数据&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;),&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; tableoid::regclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3277&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3354&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3369&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; tableoid::regclass,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;limit&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; order_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+----------+------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;hash分区数据散列分布&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入100条null数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)::text);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; order_id &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; tableoid::regclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--null数据全部都放在了remainder 0的分区上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; orders_p1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.orders_p1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+-----------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; order_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (modulus &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, remainder &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, order_id)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;hash分区表虽然没有null分区的概念，但是可以存放null数据，null数据存放在remainder 0上。&lt;/p&gt;

&lt;h4 class="relative group"&gt;混合分区
 &lt;div id="混合分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b7%b7%e5%90%88%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;分区下面也可以建立分区构成级联模式，子分区可以有不同的分区方式，这样的分区成为混合分区。



&lt;img src="https://lastdba.com/img/csdn/220e4e6f1544.png" alt="" /&gt;
创建一个混合分区：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_1000(id bigserial &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,name varchar(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;),createddate &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt;) partition &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; range(createddate);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_2001 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_1000 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) partition &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; list(name) ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_2002 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_1000 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;) partition &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; list(name) ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_2003 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_1000 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;) partition &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; list(name) ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_3001 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_2001 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_3002 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_2001 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; part_3003 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; part_2001 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;jkl&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;\d+只能看到下一级的分区&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; part_1000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dbmgr.part_1000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----------------------------+-----------+----------+---------------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bigint &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;part_1000_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; createddate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: RANGE (createddate)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: part_2001 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;), PARTITIONED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; part_2002 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;), PARTITIONED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; part_2003 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;), PARTITIONED
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; part_2001
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dbmgr.part_2001&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----------------------------+-----------+----------+---------------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bigint &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;part_1000_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; createddate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: part_1000 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: ((createddate &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (createddate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (createddate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: LIST (name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: part_3001 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; part_3002 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;def&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; part_3003 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;jkl&amp;#39;&lt;/span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时插入一条数据&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; part_1000 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(random() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 08:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; part_1000;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; createddate 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+------+------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; part_3001 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6385&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; abc &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;数据存放在最底层的子分区中&lt;/p&gt;

&lt;h4 class="relative group"&gt;声明分区特性小结
 &lt;div id="声明分区特性小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a3%b0%e6%98%8e%e5%88%86%e5%8c%ba%e7%89%b9%e6%80%a7%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有interval分区&lt;/strong&gt;。没有自带的自动新增分区功能，对于维护来说比较麻烦&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分区表的分区本身也是表&lt;/strong&gt;，这个特性比较特殊。这不仅仅造成pg可以灵活的操作子分区，更重要的是功能和特性上的影响。&lt;/li&gt;
&lt;li&gt;truncate，vacuum，analyze分区表会执行所有分区。truncate only不能在父表上执行，但可以在存数据的子表上执行，仅清除这个子分区。&lt;/li&gt;
&lt;li&gt;range，hash分区的分区键可以有多个列，list分区的分区键只能是单个列或表达式。&lt;/li&gt;
&lt;li&gt;分区父表本身是空的，最底层子分区可以存储数据&lt;/li&gt;
&lt;li&gt;default分区表会接收不在声明的范围中的数据；如果没有default分区，插入范围外的数据会直接报错&lt;/li&gt;
&lt;li&gt;如果要新增分区，需要注意default分区中是否有这个新增分区的数据&lt;/li&gt;
&lt;li&gt;partition of创建的分区会自动创建分区表上的索引、约束、行级触发器&lt;/li&gt;
&lt;li&gt;attach不会处理任何索引、约束等等对象&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;继承分区表
 &lt;div id="继承分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%bb%a7%e6%89%bf%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;继承分区也是官方支持的，它利用了PGSQL的继承表特性来实现分区表的功能。继承分区表会比声明分区表更灵活。
继承分区表的实现需要到了PGSQL中的2个功能：&lt;a href="https://www.postgresql.org/docs/current/ddl-inherit.html" target="_blank" rel="noreferrer"&gt;继承表&lt;/a&gt;和写入重定向。写入重定向可以通过&lt;a href="https://www.postgresql.org/docs/current/rules.html" target="_blank" rel="noreferrer"&gt;rule&lt;/a&gt;或者trigger来实现。&lt;/p&gt;

&lt;h4 class="relative group"&gt;创建继承分区表
 &lt;div id="创建继承分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%ba%e7%bb%a7%e6%89%bf%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;创建继承分区表示例：
&lt;strong&gt;1.创建父表&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; city_id int &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logdate date &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; peaktemp int,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; unitsales int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2.创建继承表，指定约束范围&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202308 (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; ( logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#66d9ef"&gt;INHERITS&lt;/span&gt; (measurement);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202309 (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; ( logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-10-01&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#66d9ef"&gt;INHERITS&lt;/span&gt; (measurement);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3.创建规则或触发器，将插入数据重定向到对应的继承表中&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTION&lt;/span&gt; measurement_insert_trigger()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RETURNS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;IF&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; ) &lt;span style="color:#66d9ef"&gt;THEN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; measurement_202308 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ELSIF&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-10-01&amp;#39;&lt;/span&gt; ) &lt;span style="color:#66d9ef"&gt;THEN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; measurement_202309 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ELSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RAISE &lt;span style="color:#66d9ef"&gt;EXCEPTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Date out of range. Fix the measurement_insert_trigger() function!&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;END&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IF&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;RETURN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;END&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LANGUAGE&lt;/span&gt; plpgsql;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; insert_measurement_trigger
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;BEFORE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; measurement
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EACH&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROW&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTION&lt;/span&gt; measurement_insert_trigger();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一个最基本的继承分区表就创建好了。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; measurement
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.measurement&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+---------+-----------+----------+---------+---------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; city_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logdate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; peaktemp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; unitsales &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Triggers:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; insert_measurement_trigger &lt;span style="color:#66d9ef"&gt;BEFORE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EACH&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROW&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTION&lt;/span&gt; measurement_insert_trigger()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Child tables: measurement_202308,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; measurement_202309
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;测试一下插入和查询数据&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入范围外的数据会报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt;, now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; interval &lt;span style="color:#e6db74"&gt;&amp;#39;31&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;day&lt;/span&gt; ,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: P0001: Date &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; range. Fix the measurement_insert_trigger() &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTEXT: PL&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pgSQL &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; measurement_insert_trigger() line &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; RAISE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: exec_stmt_raise, pl_exec.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3889&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入数据会重定向到子表上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt;,now(),&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查询父表会查到子表数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; tableoid::regclass,&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; measurement;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; city_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; peaktemp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; unitsales 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------+---------+------------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; measurement_202308 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;RULE和trigger&lt;/strong&gt;
除了触发器，PGSQL还可以用rule来重定向插入。
rule语句参考：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;RULE&lt;/span&gt; measurement_insert_202308 &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ( logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-01&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSTEAD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; measurement_202308 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;RULE&lt;/span&gt; measurement_insert_202309 &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ( logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-09-01&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSTEAD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; measurement_202309 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;规则和触发器的差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rule性能相较trigger更差，但在批量插入时，由于rule只有一次检查，性能会比trigger更好，但其他情况下trigger更好&lt;/li&gt;
&lt;li&gt;COPY不会触发rule，但会触发trigger。rule时可以将数据直接COPY到子表中&lt;/li&gt;
&lt;li&gt;当插入范围外数据时，rule会将数据插入到父表中，trigger则会直接报错&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;索引&lt;/strong&gt;
为了提升性能，还需要创建索引和开启constrain_exclusion。分区的索引一般都是必不可少，继承表的索引需要手动在子表上创建。
创建索引示例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_measurement_202308_logdate &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; measurement_202308 (logdate);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_measurement_202309_logdate &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; measurement_202309 (logdate);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;插入一些数据查看执行计划：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--&amp;#39;2023-08-04&amp;#39;只有1条数据，让其可以走到索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt;,now()&lt;span style="color:#f92672"&gt;+&lt;/span&gt;interval &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;day&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;),&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;),now(),&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; logdate&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-04&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; measurement measurement_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (logdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-04&amp;#39;&lt;/span&gt;::date)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_measurement_202308_logdate &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; measurement_202308 measurement_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (logdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-08-04&amp;#39;&lt;/span&gt;::date)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面的执行计划8月的分区走到了分区上的索引。constraint_exclusion默认打开了继承表的约束排除，上面的查询排除了9月分区，只扫描了8月。然而由于父表没有约束（也加不了）所以父表一定在执行计划里面，但是父表一般都是空的所以影响不大。&lt;/p&gt;

&lt;h4 class="relative group"&gt;constraint_exclusion
 &lt;div id="constraint_exclusion" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#constraint_exclusion" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;constraint_exclusion拥有控制优化器是否使用约束来减少非必要的访问表，该参数在继承分区表优化上常见，通过减少子表的访问，提升SQL的性能（该功能跟enable_partition_pruning参数类似，enable_partition_pruning用于控制声明式分区表的分区裁剪）。constraint_exclusion有3个值：
&lt;code&gt;on&lt;/code&gt;：所有表都会检查约束
&lt;code&gt;partition&lt;/code&gt;：继承表和UNION ALL子查询检查约束（默认值）
&lt;code&gt;off&lt;/code&gt;：不会检查约束
约束排除只能发生在生成执行计划时，不会发生在真正执行时（分区裁剪是可以的）。这意味着当使用绑定变量、变量值时不会发生约束排除。
例如在使用now()等优化器不知道具体值的函数时，优化器无法排除根本不需要访问的分区：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; now();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; now 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;772658&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--优化器没有排除9月的分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; logdate&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;now();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;98&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1628&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; measurement measurement_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (logdate &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; now())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; measurement_202308 measurement_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1010&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (logdate &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; now())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; measurement_202309 measurement_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;617&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: (logdate &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; now())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; idx_measurement_202309_logdate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;617&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (logdate &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; now())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;另外，约束排除本身需要检查所有子表的约束，如果子表约束过多生成执行计划的效率会受到影响，所以继承分区不建议创建过多的子分区。&lt;/p&gt;

&lt;h4 class="relative group"&gt;添加/删除继承分区表的分区
 &lt;div id="添加删除继承分区表的分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b7%bb%e5%8a%a0%e5%88%a0%e9%99%a4%e7%bb%a7%e6%89%bf%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;将一个继承分区做成普通表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202308 &lt;span style="color:#66d9ef"&gt;NO&lt;/span&gt; INHERIT measurement;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;将一个含有数据的普通表当成子表加入到继承分区表中&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202310 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; measurement &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULTS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINTS&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202310 &lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINT&lt;/span&gt; measurement_202310_logdate_check 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; ( logdate &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-10-01&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; logdate &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; DATE &lt;span style="color:#e6db74"&gt;&amp;#39;2023-11-01&amp;#39;&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--insert into measurement_202310 values(2001,&amp;#39;20231010&amp;#39;,3,3);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; measurement_202310 INHERIT measurement;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;继承分区表特性小结
 &lt;div id="继承分区表特性小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%bb%a7%e6%89%bf%e5%88%86%e5%8c%ba%e8%a1%a8%e7%89%b9%e6%80%a7%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;继承分区要比声明分区更灵活，但一些声明分区的特性也无法使用&lt;/li&gt;
&lt;li&gt;子表会继承父表上的约束，所以如果不是全局约束不要在父表上设置&lt;/li&gt;
&lt;li&gt;索引不会继承，索引只能在子表上一个个地创建&lt;/li&gt;
&lt;li&gt;声明分区只能有range、list、hash分区，继承分区可以更多，也可以是自定义的分区方式。&lt;/li&gt;
&lt;li&gt;删除一个子表不会导致触发器失效。PGSQL没有像ORACLE那样失效对象的概念（索引有失效的概念）&lt;/li&gt;
&lt;li&gt;一般来说使用trigger的插入重定向比rule效率更好&lt;/li&gt;
&lt;li&gt;新增分区时，如果触发器函数中没有该分区的规则，则需要更新触发器函数。&lt;/li&gt;
&lt;li&gt;继承分区可以多重继承&lt;/li&gt;
&lt;li&gt;约束排除不能在执行时进行排除，所以建议使用固定值进行查询&lt;/li&gt;
&lt;li&gt;使用继承分区表时，同样不要创建太多的子分区&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;pg_pathman
 &lt;div id="pg_pathman" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_pathman" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg_pathman是三方插件实现的分区表功能。&lt;a href="https://github.com/postgrespro/pg_pathman" target="_blank" rel="noreferrer"&gt;github上的pathman readme&lt;/a&gt;和&lt;a href="https://developer.aliyun.com/article/62314" target="_blank" rel="noreferrer"&gt;使用pg_pathman插件的文章&lt;/a&gt;对pathman描述和使用已经非常详细，这里仅摘几个重点汇总和做一些简单的测试。&lt;/p&gt;

&lt;h4 class="relative group"&gt;pg_pathman基本知识
 &lt;div id="pg_pathman基本知识" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_pathman%e5%9f%ba%e6%9c%ac%e7%9f%a5%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;不再更新&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;NOTE: this project is not under development anymore&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;pg_pathman支持postgres9.5到15，PostgreSQL后续版本不会再支持，已有版本也只做BUG修复，不会再新增功能。
pg_pathman的出现是因为老版本的PostgreSQL分区表功能不完善，而现在原生分区表（也就是声明分区表）已非常成熟，pg_pathman也建议使用原生分区表，存量的pg_pathman分区表也建议转移到原生分区表。曾经被许多用户认可的pg_pathman成为历史，即使不再更新，它的功能也比目前的原生分区表更多。
&lt;strong&gt;特性介绍&lt;/strong&gt;
pg_pathman功能相当强大，一些原生分区表不支持的功能pathman也支持。 pathman虽然强大但也不是完美的，在实际使用过程中问题也很多。pg_pathman特性中比较需要关注的点包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg_pathman可以通过分区管理函数管理分区。支持replace、merge、split分区操作；支持 attach、detach操作；支持interval分区&lt;/li&gt;
&lt;li&gt;pg_pathman对分区表执行计划做了很多优化&lt;/li&gt;
&lt;li&gt;pg_pathman仅支持range和hash两种分区类型&lt;/li&gt;
&lt;li&gt;pathman_config表存储分区表配置信息；提供分区任务视图&lt;/li&gt;
&lt;li&gt;分区信息缓存在内存中，以生成执行计划&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;pg_pathman基本使用
 &lt;div id="pg_pathman基本使用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_pathman%e5%9f%ba%e6%9c%ac%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;创建pathman range分区&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--普通表就是父表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; journal (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id SERIAL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dt &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt; INTEGER,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; msg TEXT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- 子分区会自动创建父表上的索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; journal(dt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;create_range_partitions(&lt;span style="color:#e6db74"&gt;&amp;#39;journal&amp;#39;&lt;/span&gt;::regclass, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;dt&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval &lt;span style="color:#e6db74"&gt;&amp;#39;1 month&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) ; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看表定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; journal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.journal&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------------+-----------+----------+-------------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;journal_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dt &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; msg &lt;span style="color:#f92672"&gt;|&lt;/span&gt; text &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;journal_dt_idx&amp;#34;&lt;/span&gt; btree (dt)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Child tables: journal_1,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_2,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_3,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_4,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_5,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; journal_6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.journal_6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------------+-----------+----------+-------------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;journal_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dt &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; msg &lt;span style="color:#f92672"&gt;|&lt;/span&gt; text &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;journal_6_dt_idx&amp;#34;&lt;/span&gt; btree (dt)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Check&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraints&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pathman_journal_6_check&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (dt &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-06-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; dt &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-07-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Inherits&lt;/span&gt;: journal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; journal (dt, &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt;, msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;, random() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;, md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; generate_series(&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;::date, &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-28&amp;#39;&lt;/span&gt;::date, &lt;span style="color:#e6db74"&gt;&amp;#39;1 hour&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入还未创建对应分区的数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; journal (dt, &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt;, msg) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;2023-07-01&amp;#39;&lt;/span&gt;::date,&lt;span style="color:#e6db74"&gt;&amp;#39;11&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看分区数据分布，已成功创建interval分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; partition, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; journal &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; partition;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; partition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_7 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;649&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; journal_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;744&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看执行计划
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--已发生分区裁剪
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; journal &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; dt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 22:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; journal journal_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (dt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 22:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; journal_1_dt_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; journal_1 journal_1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;49&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: (dt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 22:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;创建pathman hash分区&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建主表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; items (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id SERIAL &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name TEXT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; code BIGINT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建hash分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; create_hash_partitions(&lt;span style="color:#e6db74"&gt;&amp;#39;items&amp;#39;&lt;/span&gt;::regclass, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) ; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入数据 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; items (id, name, code)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;, md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text), random() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; partition, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; items &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; partition;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; partition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;344&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;318&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;338&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; items
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.items&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+---------+-----------+----------+-----------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;items_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; text &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; code &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bigint &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;items_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Child tables: items_0,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_1,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; items_1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.items_1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+---------+-----------+----------+-----------------------------------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;items_id_seq&amp;#39;&lt;/span&gt;::regclass) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; text &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; code &lt;span style="color:#f92672"&gt;|&lt;/span&gt; bigint &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;items_1_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Check&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraints&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pathman_items_1_check&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (get_hash_part_idx(hashint4(id), &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Inherits&lt;/span&gt;: items
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; partition, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; items &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; partition;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; partition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;344&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;318&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;338&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;pg分区表的优劣
 &lt;div id="pg分区表的优劣" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e4%bc%98%e5%8a%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;分区表的优势
 &lt;div id="分区表的优势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e4%bc%98%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SQL性能提升。在某些场景下，比如把大量的数据分成多个分区，而SQL只需要查那一个分区的数据时，SQL性能可能会极大的提升&lt;/li&gt;
&lt;li&gt;分区可以和索引配合使用。比如访问一个分区上的一个索引要比访问一个未分区的大索引要更高效。&lt;/li&gt;
&lt;li&gt;删除一个分区比删除多行数据更高效。这在时间范围分区中很常见，删除一个用不到的历史分区是非常快的，但是如果没有分区，delete删除数据不仅慢还需要额外的维护操作&lt;/li&gt;
&lt;li&gt;vacuum更快。一个大表在回收旧版本信息或收集统计信息时会非常慢，在vacuum还没执行完的时候可能SQL已经存在问题了。如果有分区的话，vacuum会快很多。&lt;/li&gt;
&lt;li&gt;IO分散能力。不同的分区可以放在不同的路径、不同的磁盘上。极少使用数据可以放在便宜的磁盘上。&lt;/li&gt;
&lt;li&gt;更多的维护技巧。直接维护一个大表是非常困难的，比如一个极大的表做vacuum时就有很多问题，而分区表的各个分区可以单独运行vacuum。不仅如此，attach/detach、本地索引/约束等可以在很多场景中灵活使用。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;分区表的劣势
 &lt;div id="分区表的劣势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e5%8a%a3%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在pgsql中，每个分区表的分区都可以当成普通表来对待。分区表过多会导致SQL解析时间较长和更多的内存负载，甚至报错。参考之前的文章&lt;a href="https://editor.csdn.net/md/?articleId=131497779" target="_blank" rel="noreferrer"&gt;较少的分区也报错too many range table entries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;即使分区过多没有报错，且在生成执行计划的时候没有做分区剪裁（执行的时候有可能做），那么explain出来的执行计划会非常多，此时日志中也会打印长长的执行计划影响日志阅读。&lt;/li&gt;
&lt;li&gt;一些奇怪的问题：&lt;a href="https://mp.weixin.qq.com/s?__biz=MzUyOTAyMzMyNg==&amp;amp;mid=2247489813&amp;amp;idx=1&amp;amp;sn=22360e2bfd40fc2d0caed0a9d825b1d4&amp;amp;chksm=fa663124cd11b832953e789127927ffa0d63d6c948ca8934d5317b8eaae6e71374041ec038f7&amp;amp;mpshare=1&amp;amp;srcid=0728JrXnHdxnfgRVzqosBNcv&amp;amp;sharer_sharetime=1690509489198&amp;amp;sharer_shareid=0412ea33e50b471b98d8859a5c431367&amp;amp;from=singlemessage&amp;amp;scene=1&amp;amp;subscene=10000&amp;amp;sessionid=1690509419&amp;amp;clicktime=1690509545&amp;amp;enterid=1690509545&amp;amp;ascene=1&amp;amp;fasttmpl_type=0&amp;amp;fasttmpl_fullversion=6785798-en_US-zip&amp;amp;fasttmpl_flag=0&amp;amp;realreporttime=1690509545257&amp;amp;devicetype=android-29&amp;amp;version=28002658&amp;amp;nettype=WIFI&amp;amp;abtest_cookie=AAACAA%3D%3D&amp;amp;lang=en&amp;amp;countrycode=CN&amp;amp;exportkey=n_ChQIAhIQCCtq2jm3UsFznlVjxFEOWBLaAQIE97dBBAEAAAAAABKTCFyWAsoAAAAOpnltbLcz9gKNyK89dVj0LyxnG1pA6NiO6PHIsQ0Hy2N7QRbizb9SHdquaFOpOqANqG8jLDcioswZyRnYknjG4bSqNIIKm%2BpRIlK%2FVJxuwolH2%2FQJKSLg4YjccDktYYscUDvYSfHFx1ScEXZkOkbVqrvbBCPy6Gh2GnzulFuuIU68afNtsoBdzZTqHYbL0BfsAUhsz1iGAfSep642UT2CBpWSHWJQvndnwhZxjJ6%2FWO%2FI%2FqwncggiVeDNiv4vwXhluDNn&amp;amp;pass_ticket=mrpzS3wggBDzL9Ua2FmX5v1rYh6zKOnQ4og6oKcKv0ZXRfNBSUpSkGdTAcfXqgDo&amp;amp;wx_header=3" target="_blank" rel="noreferrer"&gt;不同用户查看到不同的执行计划&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;分区表的限制
 &lt;div id="分区表的限制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e9%99%90%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;没有原生的自动创建分区功能&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;只支持分区索引，不支持全局索引&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;主键必须包含分区键。postgresql目前只能在各自的分区内判断唯一性，所以有这个限制。oracle和mysql都没有这种限制。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;唯一索引必须包含分区键。postgresql目前只能在各自的分区内判断唯一性。同理主键&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;无法创建定义在全局的约束&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;INSERT的BEFORE ROW触发器不能更新insert的那个分区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;临时表分区和普通表分区不能在同一分区表下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;声明式分区的父表子表的列必须一致；继承式分区的子表可以比父表的列更多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;声明式分区CHECK和NOT NULL约束总是继承的，不能单独设置分区的这两种约束&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;range 不能存储NULL值；hash分区没有null分区的概念，但可以存储null值，null值存放在remainder 0分区上；list分区可以显示创建null分区存放null数据&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;什么时候该使用分区表？
 &lt;div id="什么时候该使用分区表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e8%af%a5%e4%bd%bf%e7%94%a8%e5%88%86%e5%8c%ba%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;首先使用分区表必须要了解分区表所带来的优劣势和使用限制，比如数据量很大的时候分区可以带来性能提升，冷热数据分离也更好管理分区数据等等。应该结合本身业务情况、硬件资源选择是否分区和如何分区。但是总会有开发人员会问到底多少数据量该分区等等的问题，使用分区表的建议只能给出一个笼统的回答，如果你不知道怎么分区，可以参考以下建议（如果足够了解表分区，请忽略）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表数据够大，而表上的sql总是或可以是带有分区键字段的时候&lt;/li&gt;
&lt;li&gt;冷热数据分离明显。比如新数据都在新的当月分区插入，老的11个月分区都是只读数据的情况&lt;/li&gt;
&lt;li&gt;vaccum已经跑不过来了&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;分区表的权限
 &lt;div id="分区表的权限" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e6%9d%83%e9%99%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;权限问题是分区表知识点中讨论的比较少的，但是它仍然值得关注。
由于PostgreSQL数据库有“分区子表也是普通表”这样的概念，这与其他几个常见的数据库（Oracle、mysql）是不同的。比如在oracle中不需要关心分区子表的权限，但是在pg中却需要关注权限问题。&lt;/p&gt;
&lt;p&gt;partition of/attach不会将主表的权限继承给子表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--把分区去表的select授权给一个普通用户
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; userlzl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看权限，只有主表有授权，存量分区子表不会自动授权
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; grantee,table_schema,&lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt;,privilege_type &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.table_privileges &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; grantee&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;userlzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grantee &lt;span style="color:#f92672"&gt;|&lt;/span&gt; table_schema &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; privilege_type 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------------+---------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;--partition of方式创建一个分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION1_202303 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--attach方式创建一个分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; lzlpartition1_202304
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULTS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINTS&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 attach partition lzlpartition1_202304 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-05-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--再次查看权限，新增的子分区不会自动授权给其他用户（但是新增子分区权限会自动授权给owner）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; grantee,table_schema,&lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt;,privilege_type &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; information_schema.table_privileges &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; grantee&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;userlzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grantee &lt;span style="color:#f92672"&gt;|&lt;/span&gt; table_schema &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; privilege_type 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------------+---------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userlzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;目前来看userlzl 这个用户对所有子表都没有访问权限，但是有主表的权限
此时userlzl可以通过主表访问分区数据，但不能通过直接访问子表访问数据&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; userlzl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; now connected &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dbmgr&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;userlzl&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLPARTITION1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-02 10:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+----------------------------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2159&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; d05d716da126ff4b44d934344cc4dd7a &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLPARTITION1_202301 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-02 10:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42501&lt;/span&gt;: permission denied &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: aclcheck_error, aclchk.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3466&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为attach/detach不会处理权限，此时如果我们把分区detach出来，这个分区同样不能被userlzl访问&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202303;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;dp&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202303;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;privileges&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Schema&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;privileges&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;privileges&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Policies 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----------------------+-------+-------------------+-------------------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202303 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLPARTITION1_202301 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-02 10:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42501&lt;/span&gt;: permission denied &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202301 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由此可知&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分区子表和主表PostgreSQL在数据库中都是以普通表的形式存在，他们都有各自的权限体系&lt;/li&gt;
&lt;li&gt;如果没有子表权限而主表有权限同样可以访问子表数据&lt;/li&gt;
&lt;li&gt;partition of、attach/detach都不会处理权限问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是，分区表权限并不是仅仅控制是否能够访问，没有分区子表权限可能导致执行计划异常，参考文章：&lt;a href="https://mp.weixin.qq.com/s?__biz=MzUyOTAyMzMyNg==&amp;amp;mid=2247489813&amp;amp;idx=1&amp;amp;sn=22360e2bfd40fc2d0caed0a9d825b1d4&amp;amp;chksm=fa663124cd11b832953e789127927ffa0d63d6c948ca8934d5317b8eaae6e71374041ec038f7&amp;amp;mpshare=1&amp;amp;srcid=0728JrXnHdxnfgRVzqosBNcv&amp;amp;sharer_sharetime=1690509489198&amp;amp;sharer_shareid=0412ea33e50b471b98d8859a5c431367&amp;amp;from=singlemessage&amp;amp;scene=1&amp;amp;subscene=10000&amp;amp;sessionid=1690509419&amp;amp;clicktime=1690509545&amp;amp;enterid=1690509545&amp;amp;ascene=1&amp;amp;fasttmpl_type=0&amp;amp;fasttmpl_fullversion=6785798-en_US-zip&amp;amp;fasttmpl_flag=0&amp;amp;realreporttime=1690509545257&amp;amp;devicetype=android-29&amp;amp;version=28002658&amp;amp;nettype=WIFI&amp;amp;abtest_cookie=AAACAA%3D%3D&amp;amp;lang=en&amp;amp;countrycode=CN&amp;amp;exportkey=n_ChQIAhIQCCtq2jm3UsFznlVjxFEOWBLaAQIE97dBBAEAAAAAABKTCFyWAsoAAAAOpnltbLcz9gKNyK89dVj0LyxnG1pA6NiO6PHIsQ0Hy2N7QRbizb9SHdquaFOpOqANqG8jLDcioswZyRnYknjG4bSqNIIKm%2BpRIlK%2FVJxuwolH2%2FQJKSLg4YjccDktYYscUDvYSfHFx1ScEXZkOkbVqrvbBCPy6Gh2GnzulFuuIU68afNtsoBdzZTqHYbL0BfsAUhsz1iGAfSep642UT2CBpWSHWJQvndnwhZxjJ6%2FWO%2FI%2FqwncggiVeDNiv4vwXhluDNn&amp;amp;pass_ticket=mrpzS3wggBDzL9Ua2FmX5v1rYh6zKOnQ4og6oKcKv0ZXRfNBSUpSkGdTAcfXqgDo&amp;amp;wx_header=3" target="_blank" rel="noreferrer"&gt;不同用户查看到不同的执行计划&lt;/a&gt;
这个问题是一个偶发现象，导致超级用户和一般用户看到的sql执行计划不一致，实际上业务SQL执行计划异常却看不出来，比较难定位。分区子表有各自的统计信息，子表权限与父表不一致（即便是partition of创建的分区），导致用户可以通过主表访问子表的数据，却不能查看子表的统计信息。权限问题导致了执行计划产生差异。
这与“&lt;em&gt;权限只控制是否能访问表，不控制如何访问表&lt;/em&gt;”的一般概念是违背的，所以需要注意这个权限问题。
为了提供子表统计信息权限，建议显示对用户授权所有子表查询权限，就可以避免以上问题&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_partition_allname &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; username;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;分区表的维护
 &lt;div id="分区表的维护" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e7%bb%b4%e6%8a%a4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;分区表ATTACH/DETACH基本操作
 &lt;div id="分区表attachdetach基本操作" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8attachdetach%e5%9f%ba%e6%9c%ac%e6%93%8d%e4%bd%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;attach/detach可以将一个已存在的表作为分区添加/分离分区表。attach/detach在维护工作中很有用。
先来看看&amp;quot;create table&amp;hellip;partition of&amp;quot;方式添加分区和&amp;quot;drop table&amp;quot;删除分区的锁情况&lt;/p&gt;
&lt;p&gt;锁矩阵：https://www.postgresql.org/docs/current/explicit-locking.html&lt;/p&gt;
&lt;p&gt;申请的锁：https://postgres-locks.husseinnasser.com&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;partition of新增分区&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 开启一个事务，只读数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+----------------------------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;8249&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;ac66bb53d31bc6124294238d6410c &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁情况。读取一个分区数据时，要在子分区和主表上同时获得锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+-----------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 partition of方式添加分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION1_202305 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-05-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-06-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 再次查看锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;308525&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#75715e"&gt;--此为partition of会话
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session4 再随便来一个查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session4再次查看锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;308525&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;84774&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#75715e"&gt;--查询阻塞&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;partition of方式新增分区时，会申请主表的 AccessExclusiveLock，等待主表一切事务的同时也会阻塞主表的一切事务。



&lt;img src="https://lastdba.com/img/csdn/851906be0f93.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;虽然partition of语句本身执行很快，但是如果遇到主表上有长事务，那么分区表上的所有操作都会长时间停滞。如果没有停机窗口，直接使用partition of方式新增分区是不推荐的。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;drop table删除分区&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 再次开启只读事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 删除分区表的子分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202305;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;308525&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;drop table删除子分区时，会申请主表上的AccessExclusiveLock，等待一切和阻塞一切。同样的在生产环境需要谨慎使用。&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;attach添加分区&lt;/strong&gt;
attach将一个已存在的普通表附加到分区表上
虽然attach跟partition of都可以添加分区，但是需要注意&lt;strong&gt;ATTACH不会自动创建索引、约束、默认值、行级触发器&lt;/strong&gt;，这点跟partition of是不同的。
先创建一个表&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--减少繁琐的ddl，like方式创建表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; lzlpartition1_202305
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULTS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINTS&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再观察attach的是否被阻塞&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 开启读写事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--dml语句会获得分区主表和对应分区子表的RowExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 attach新建的表到分区主表上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 attach partition lzlpartition1_202305 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-05-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-06-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;attach只会申请SHARE UPDATE EXCLUSIVE锁，比ACCESS EXCLUSIVE低很多。



&lt;img src="https://lastdba.com/img/csdn/b23cc350250f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;attach与读写都互不阻塞，所以推荐以attach方式添加分区，不影响业务，可在线执行。&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;detach删除分区&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;detach将一个分区脱离分区表，成为一个普通表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 保持dml事务不提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 detach一个分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202305;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;311449&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;308525&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;308525&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;detach跟attach不同，detach申请了主表的AccessExclusiveLock，等待一切和阻塞一切。&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;detach concurrently&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL 14开始，detach新增了两种语法CONCURRENTLY 和FINALIZE&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;ALTER TABLE [ IF EXISTS ] &lt;em&gt;&lt;code&gt;name&lt;/code&gt;&lt;/em&gt;
DETACH PARTITION &lt;em&gt;&lt;code&gt;partition_name&lt;/code&gt;&lt;/em&gt; [ CONCURRENTLY | FINALIZE ]&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;detach concurrently内部会开启两次事务，第一次事务会在主表和子表上都申请SHARE UPDATE EXCLUSIVE锁，分区会标记为正在detach的状态，此时会等待分区表上的所有事务提交。一旦这些事务全部都提交了，第二次事务会申请主表上的 SHARE UPDATE EXCLUSIVE锁和那个子表上ACCESS EXCLUSIVE锁，随后detach concurrently完成。&lt;/p&gt;
&lt;p&gt;另外，detach concurrently后的子分区，会保留约束，由分区约束转化为check约束保留在detach后的表上&lt;/p&gt;
&lt;p&gt;DETACH CONCURRENTLY的限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DETACH CONCURRENTLY不能放在事务块中&lt;/li&gt;
&lt;li&gt;分区表不能有default分区&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;concurrently的阻塞情况：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 detach concurrently
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 concurrently;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;); &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 concurrently; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Lock&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3947&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pid,query,wait_event_type,wait_event &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_activity; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--detach会话是3940，非常奇怪，detach的等待事件是virtualxid，等待事件类型是Lock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看锁的情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;,relation,virtualtransaction,pid,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; pid &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualtransaction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------+----------+----------+--------------------+------+------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16387&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;40969&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;179&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16387&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;40963&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;179&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;179&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;179&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时的detach还没有等待表上的锁，而是在等待virtualxid的ShareLock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session4 做个插入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;12345&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#66d9ef"&gt;no&lt;/span&gt; partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; relation &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;found&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: Partition &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; the failing &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;contains&lt;/span&gt; (date_created) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;12345&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--此时detach的分区已经不能插入，其他分区可以插入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--如果通过分区插入会怎样呢？可以正常插入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;12345&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--注意此时它还是个分区表的分区，还不是一个普通表，不过它已经被标记为不可用了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--\d+查看分区处于DETACH PENDING状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) (DETACH PENDING),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzlpartition1_202302 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--把insert的session1提交/回滚
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2立即完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 concurrently;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;FINALIZE：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 01:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 detach concurrently，手动cancel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 concurrently;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;^&lt;/span&gt;CCancel request sent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: canceling &lt;span style="color:#66d9ef"&gt;statement&lt;/span&gt; due &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; request
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--\d+查看分区表，分区处于DETACH PENDING状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) (DETACH PENDING),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzlpartition1_202302 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--DETACH PENDING的分区，SQL已经不会去访问了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;752&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;81&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;38881&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--finalize使之完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 finalize; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;lzldb&lt;span style="color:#f92672"&gt;-#&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+------+--------------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3940&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ShareUpdateExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3691&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--3940，finalize申请了分区主表的ShareUpdateExclusiveLock和子表的AccessExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--由于是插入的是数据的分区刚好是detach的分区，所以发生等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=!&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2立即完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301 finalize; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;虽然detach的分区会申请8级锁，但是一般业务也没有直接通过子分区写数据的，所以只需要关注分区表的长事务尽快完成就行，一般不需要担心造成该分区子表上的后续阻塞。&lt;/p&gt;
&lt;p&gt;在线detach小结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;detach concurrently的阻塞情况跟CIC有点类似，不会阻塞其他事务，但是其本身会等待已有的事务完成，这点在lock上不太容易看出来&lt;/li&gt;
&lt;li&gt;在detach concurrently期间分区会处于DETACH PENDING中间状态，该状态有点类似invisible，sql不会找到这个分区&lt;/li&gt;
&lt;li&gt;如果是长事务导致的DETACH PENDING，应及时结束长事务；如果是中断导致的DETACH PENDING，可以使用FINALIZE使其完成detach。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;利用约束减少attach时间
 &lt;div id="利用约束减少attach时间" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%a9%e7%94%a8%e7%ba%a6%e6%9d%9f%e5%87%8f%e5%b0%91attach%e6%97%b6%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;分区数据情况，准备操作一个较大分区的attach操作&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; partition, &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; partition;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; partition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2592001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzlpartition1_202302 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38881&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意这个202301的分区有一个partition constraint&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1_202301&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: lzlpartition1 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_202301_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id, date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;detach分区&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--detach后，partition constraint就没有了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1_202301&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_202301_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id, date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;不添加check约束，attach&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 attach partition lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;343&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;498&lt;/span&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由于要扫描分区数据是否满足分区范围，attach耗时300+ms&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;添加check约束，attach&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 detach partition lzlpartition1_202301;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; chk_202301 &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;355&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;458&lt;/span&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面添加check约束的耗时跟没有check时的attach操作耗时差不多，因为添加check约束同样也要扫描检查所有数据。
check约束添加完后再attach，此时的attach操作非常快就能完成&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 attach partition lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;480&lt;/span&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;删除check约束&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202301;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1_202301&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: lzlpartition1 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_202301_pkey&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;, btree (id, date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Check&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraints&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;chk_202301&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意，check constraint和partition constraint是不一样的概念，虽然他俩的约束内容可以是一致的。attach使用了check约束但是不会进行合并，可以显式删除这个多余的check。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; chk_202301;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;另外，需要关注drop constraint申请了当前子分区上AccessExclusiveLock，这是最高级别的锁，会阻塞任何操作。所以当前子分区上有事务，谨慎执行drop constraint。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;448243&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;448243&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;444399&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;444399&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#75715e"&gt;--这个就是drop constraint会话
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;448243&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;so，
&lt;strong&gt;在attach分区时，先添加check约束是比较有用，它可以减少attach的执行时间，数据检查在attach前完成就可以了&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;分区表新增分区的正确姿势
 &lt;div id="分区表新增分区的正确姿势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e6%96%b0%e5%a2%9e%e5%88%86%e5%8c%ba%e7%9a%84%e6%ad%a3%e7%a1%ae%e5%a7%bf%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;我们现在知道，attach可以在线执行，而partition of/drop table/detach都会申请等待和阻塞一切的AccessExclusiveLock
so，
&lt;strong&gt;建议用attach新建分区。partition of/detach都会等待和阻塞一切事务，而attach不会被只读/DML事务阻塞&lt;/strong&gt;
所以添加分区应该使用attach，并提前创建check约束，删除约束时需要关注长事务问题。
&lt;strong&gt;分区表添加分区的正确姿势&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--减少繁琐的ddl，like方式创建表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; lzlpartition1_202303
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULTS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INCLUDING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINTS&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--参考其他分区的Partition constraint，添加表的check约束，减少attach检查约束的时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202303 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; chk_202303 &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--attach方式添加分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION1 attach partition LZLPARTITION1_202303 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-03-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-04-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--可选。在新分区有事务之前，删除多余的check约束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1_202303 &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; chk_202303;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;分区索引的锁
 &lt;div id="分区索引的锁" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e7%b4%a2%e5%bc%95%e7%9a%84%e9%94%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;只读事务时创建/删除分区索引&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当分区上有共享锁时&lt;code&gt;AccessShareLock&lt;/code&gt;，也就是分区表上有查询事务的情况下
CREATE INDEX ON lzlpartition1创建成功（注意没有加concurrently）；DROP INDEX lzlpartition1失败&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 开启事务，读取分区表数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-02 00:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;86401&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 创建索引，成功
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_datecreated &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1(date_created);;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 删除索引，等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_datecreated;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+---------------------------+------------+---------------+--------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301_pkey &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;99598&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;create index没有申请表上的AccessExclusiveLock，但是drop index申请了表上的AccessExclusiveLock。
从这个的例子可以得出：
&lt;strong&gt;只读事务不会阻塞创建索引，但会阻塞删除索引&lt;/strong&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;更新事务时创建/删除分区索引&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 开启更新事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 10:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 创建分区索引，等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_datecreated &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+---------------------------+------------+---------------+--------+------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301_pkey &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;99598&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;create index会话（99598）申请分区主表的ShareLock锁，DML事务会话（300371 ）持有该子分区和主表的RowExclusiveLock



&lt;img src="https://lastdba.com/img/csdn/9fc4b97314bd.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;create index（无concurrently）会话申请主表ShareLock；
只读事务会话申请主表和子表的AccessShareLock；
更新事务会话申请主表和子表的RowExclusiveLock；
==&amp;gt;
AccessShareLock不阻塞ShareLock，所以查询不阻塞create index（无concurrently）；
RowExclusiveLock阻塞ShareLock，所以DML阻塞create index（无concurrently）；&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;concurrently创建分区索引&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;注意：在分区表上不能用concurrently创建索引&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;A000: cannot &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1&amp;#34;&lt;/span&gt; concurrently
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: DefineIndex, indexcmds.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;665&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有个patch &lt;a href="https://commitfest.postgresql.org/35/2815/" target="_blank" rel="noreferrer"&gt;https://commitfest.postgresql.org/35/2815/&lt;/a&gt;在解决这个问题。&lt;/p&gt;
&lt;p&gt;目前可以在分区子表上concurrently创建索引。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1 仍然使用之前的DML事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 concurrently方式在子表上创建索引，等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated_202301 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 查询锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+---------------------------+------------+---------------+--------+--------------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301_pkey &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;99598&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ShareUpdateExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;concurrently申请的锁降低了一级，跟ROW EXCL&lt;strong&gt;不冲突了&lt;/strong&gt;。锁都不冲突了，但是为什么concurrently本身还是被阻塞了呢？&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;it must wait for all existing transactions that could potentially modify or use the index to terminate.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;官方文档解释concurrently需要等待潜在修改/使用索引的事务完成，我们这里的update语句更新了索引字段，所以concurrently需要等待它完成。
&lt;strong&gt;虽然concurrently本身因为之前的DML语句没有完成，但是这也有一个好处：concurrently不会阻塞后续的DML语句&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--concurrently没有完成的情况下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session4 更新一条记录
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 12:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;汇总分区索引的锁问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分区表上只读/读写/创建索引时的锁跟普通表是差不多的，只需要注意事务会在分区主表和子表上都会加锁，所以后续阻塞链的锁更重时，会影响所有分区&lt;/li&gt;
&lt;li&gt;只读事务不会阻塞create index，但是会阻塞drop index&lt;/li&gt;
&lt;li&gt;DML会阻塞create index，也会阻塞create index concurrently，但是concurrently不会阻塞DML&lt;/li&gt;
&lt;li&gt;虽然在分区表上create index可以自动在各个分区和未来分区上创建索引，但是由于阻塞问题不建议在生产直接使用&lt;/li&gt;
&lt;li&gt;不能在分区主表上直接使用concurrently，所以需要在各个分区子表上concurrently创建索引&lt;/li&gt;
&lt;li&gt;concurrently不会阻塞后续的事务，但本身会被之前的长事务阻塞，也可能导致创建的索引失效，所以需要关注长事务问题&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;创建分区索引的正确姿势
 &lt;div id="创建分区索引的正确姿势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%9b%e5%bb%ba%e5%88%86%e5%8c%ba%e7%b4%a2%e5%bc%95%e7%9a%84%e6%ad%a3%e7%a1%ae%e5%a7%bf%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;虽然不能以concurrently方式在分区表上创建索引，但可以在分区子表用concurrently创建索引，需要用到语法：
&lt;code&gt;CREATE INDEX ON ONLY&lt;/code&gt; ：在主表上创建一个无效索引，不会在子分区自动创建索引
&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; ：concurrently方式在子分区上创建索引
&lt;code&gt;ALTER INDEX .. ATTACH PARTITION&lt;/code&gt;：将分区索引ATTACH到主索引上，所有子分区索引ATTACH后，分区主表索引自动标记为有效。
不过在执行这些命令时仍然需要关注锁的情况&lt;/p&gt;
&lt;p&gt;下面观察上面两个语句申请锁和阻塞的情况：
（过程中全程开启session1的DML显示事务）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ONLY创建索引的阻塞情况&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; IDX_DATECREATED &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; lzlpartition1(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看锁情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+--------+------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;448243&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;448243&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;444399&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ONLY创建索引会申请ShareLock锁，ShareLock跟RowExclusiveLock是相互阻塞的。所以，虽然ONLY本身执行会很快，但是ONLY创建索引也不是无脑使用。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将DML事务结束后，ONLY创建索引完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_datecreated&amp;#34;&lt;/span&gt; btree (date_created) INVALID&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;CREATE INDEX ON ONLY&lt;/code&gt;在分区主表上创建了一个失效索引，且不会在子分区创建索引。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;ATTACH索引的阻塞情况&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将ONLY索引创建完成后，再开启session1的DML显示事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1111&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 concurrently创建子分区的索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated_202302 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#75715e"&gt;--202302分区索引创建完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated_202304 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#75715e"&gt;--202302分区索引创建完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated_202301 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----创建202302分区索引等待&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;concurrently会等待潜在使用索引的事务完成，我们这里的显示事务只插入了202301分区，也只有这个分区的concurrently创建索引没有完成。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--完成session1的DML显示事务，等待索引完成后，然后再次开启事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;1111&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:01&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2 attach索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_datecreated ATTACH PARTITION idx_datecreated_202302;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#75715e"&gt;--成功ATTACH
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; idx_datecreated
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Partitioned &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.idx_datecreated&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Definition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+------+--------------+---------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; yes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;btree, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1&amp;#34;&lt;/span&gt;, invalid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: idx_datecreated_202302 &lt;span style="color:#75715e"&gt;--202302子分区索引已经attach，索引仍为invalid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: btree
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将剩余的子分区索引全部attach
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_datecreated ATTACH PARTITION idx_datecreated_202301;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#75715e"&gt;--成功ATTACH
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_datecreated ATTACH PARTITION idx_datecreated_202304;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#75715e"&gt;--成功ATTACH 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--完成所有子分区索引attach后，主表索引自动有效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; idx_datecreated
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Partitioned &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.idx_datecreated&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Definition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+------+--------------+---------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; yes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;btree, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.lzlpartition1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: idx_datecreated_202301,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_datecreated_202302,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_datecreated_202304
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: btree&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;attach不会被DML阻塞，直接完成。此时用partition of创建的新分区也会自动创建子分区索引。&lt;/p&gt;
&lt;p&gt;综上所述，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CREATE INDEX ON ONLY&lt;/code&gt;会申请&lt;code&gt;ShareLock&lt;/code&gt;锁，跟DML申请的&lt;code&gt;RowExclusiveLock&lt;/code&gt;是相互阻塞的&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;会申请&lt;code&gt;ShareUpdateExclusiveLock&lt;/code&gt;锁，不会阻塞DML申请的&lt;code&gt;RowExclusiveLock&lt;/code&gt;，但是&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;需要等待DML事务完成才能完成（concurrently可以获得锁，但不能完成）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ALTER INDEX .. ATTACH PARTITION&lt;/code&gt;会申请&lt;code&gt;AccessShareLock&lt;/code&gt;，这是最轻的锁，跟DML申请的&lt;code&gt;RowExclusiveLock&lt;/code&gt;相互不阻塞。&lt;/li&gt;
&lt;li&gt;查询申请的是&lt;code&gt;AccessShareLock&lt;/code&gt;最轻的锁，除非DDL申请&lt;code&gt;AccessExclusiveLock&lt;/code&gt;最重的锁，不然不会发生阻塞&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，直接在分区上create index会阻塞DML，是不可取的
&lt;strong&gt;创建分区索引的正确姿势&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--ONLY方式在分区主表上创建失效索引。快，会阻塞后续dml，会影响业务，需要关注长事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; IDX_DATECREATED &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; lzlpartition1(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--CONCURRENTLY在各个分区子表上创建索引。慢，不会阻塞后续dml，不会影响业务，但需要关注DML长事务防止本身失败
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; concurrently idx_datecreated_202302 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302(date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--所有索引attach。快，不会发生业务阻塞
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_datecreated ATTACH PARTITION idx_datecreated_202302;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;分区表添加主键和唯一索引
 &lt;div id="分区表添加主键和唯一索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e6%b7%bb%e5%8a%a0%e4%b8%bb%e9%94%ae%e5%92%8c%e5%94%af%e4%b8%80%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;“主键索引”功能上等于“唯一索引+null约束”（但是主键只能有一个）。分区表创建唯一索引可以参考上面的索引创建最佳实践：only创建主表索引、concurrently创建子表索引、attach。
而主键虽然支持普通表using index语法，但是目前不支持分区表这样使用：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINT&lt;/span&gt; pk_id_date_created &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_uniq;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;A000: &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USING&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; supported &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; partitioned tables
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;LOCATION&lt;/span&gt;: ATExecAddIndexConstraint, tablecmds.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8032&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;也就是说可以通过提前创建not null约束+attach索引的方式创建一个非空的唯一索引，但是最后一步using index添加主键却不行。&lt;/p&gt;
&lt;p&gt;下面看下直接添加/删除主键的阻塞情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;直接删除主键&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session 1 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;318&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 22:00:00&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; date_created 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+----------------------------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;7715&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; beee680a86e1d12790489e9ab4a4351b &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;--session2 删除主键等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; lzlpartition1_pkey;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;--session3 观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+---------------------------+------------+---------------+-------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301_pkey &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21659&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21659&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;95016&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;95016&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21659&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;删除主键申请的是AccessExclusiveLock，阻塞一切&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;直接添加主键&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1事务结束，session2的删除主键完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session1再次开启只读事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session2在分区表上添加主键，等待
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;ADD&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;(id, date_created);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--session3 观察锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; l.locktype,d.datname,r.relname,l.virtualxid,l.transactionid,l.pid,l.&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt;,l.&lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks l &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_database d &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.&lt;span style="color:#66d9ef"&gt;database&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.oid &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_class r &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; l.relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r.oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relname &lt;span style="color:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%lzlpartition1%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;granted&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+---------+----------------------+------------+---------------+-------+---------------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1_202301 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21659&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;95016&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;95016&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; f &lt;span style="color:#75715e"&gt;--添加主键的会话
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21659&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;添加主键在主表上申请AccessExclusiveLock，阻塞一切。
分区表上添加索引很慢，主键又会造成后续的阻塞，目前没有影响较小的在分区表上添加主键的办法。虽然没有达到目的，可以考虑用“attach唯一索引+非空约束”的办法；或者只能申请较长的停分区表业务，等待创建索引完成；或者通过第三方同步工具将数据插入一个带主键的分区表。&lt;/p&gt;

&lt;h3 class="relative group"&gt;hash分区表添加分区
 &lt;div id="hash分区表添加分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hash%e5%88%86%e5%8c%ba%e8%a1%a8%e6%b7%bb%e5%8a%a0%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果新增后的分区数为之前的整数倍，那么我们将会知道新分区的数据来自哪个老分区。比如将原本只有3个分区的hash分区表做成6个分区的，我们可以知道分区数据来源



&lt;img src="https://lastdba.com/img/csdn/84a32ff4147c.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;虽然了解了这种简单的数据特性，但实际情况可能没有什么用，因为新分区的hash分区总是被暴力插入的。从操作上“3-&amp;gt;4”的新增分区操作和“3-&amp;gt;6”的新增分区操作没有什么区别。
目前成熟的数据同步工具已经非常多了，比如使用dts把表插入到新表中然后做表切换，停机时间会很短，生产环境应优先选择这个方案。
下面是主要是测试和观察hash分区表手动新增整数倍分区时的操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分区信息&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; tableoid::regclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3377&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3354&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; orders_p2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3369&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;2. detach分区
 3个分区的hash原生分区表再添加3个分区
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders DETACH PARTITION orders_p1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders DETACH PARTITION orders_p2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders DETACH PARTITION orders_p3;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;rename分区&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p1 &lt;span style="color:#66d9ef"&gt;RENAME&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; bak_orders_p1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p2 &lt;span style="color:#66d9ef"&gt;RENAME&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; bak_orders_p2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p3 &lt;span style="color:#66d9ef"&gt;RENAME&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; bak_orders_p3;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;在老表上创建6个hash分区&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p1 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p2 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p3 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p4 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p5 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; orders_p6 PARTITION &lt;span style="color:#66d9ef"&gt;OF&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (MODULUS &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, REMAINDER &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;查看分区信息
注意分区约束使用的函数&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; orders_p1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.orders_p1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+-----------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; order_id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: orders &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; (modulus &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, remainder &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, order_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;计算老分区数据需要插入到哪个新分区上
例如原先为modulus 3，remainder 0的分区，需要把数据分别插入到modulus 6，remainder0和3两个分区中。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bak_orders_p1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1776&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bak_orders_p1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1601&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; bak_orders_p1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3377&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;6.通过分区子表插入数据
可以直接把数据插入对应的分区子表上，而不是通过分区主表插入&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p1 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p2 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p2 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p3 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p3 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p4 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p5 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p2 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; orders_p6 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bak_orders_p3 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; satisfies_hash_partition(&lt;span style="color:#e6db74"&gt;&amp;#39;412053&amp;#39;&lt;/span&gt;::oid, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, order_id)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="7"&gt;
&lt;li&gt;验证3个老分区的数据已插入到6个新分区中&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; tableoid::regclass,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; orders &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; tableoid::regclass;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tableoid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-----------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p3 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1665&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p5 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1678&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1776&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p6 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1689&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p4 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1601&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orders_p2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1691&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;修改分区字段长度索引会重建
 &lt;div id="修改分区字段长度索引会重建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bf%ae%e6%94%b9%e5%88%86%e5%8c%ba%e5%ad%97%e6%ae%b5%e9%95%bf%e5%ba%a6%e7%b4%a2%e5%bc%95%e4%bc%9a%e9%87%8d%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;修改字段需要考虑三个方面：表重写、索引重建、统计信息丢失&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改字段类型、字段长度减少都会重写表&lt;/li&gt;
&lt;li&gt;字段长度增加仅会丢失统计信息，一个例外情况是将长度改小（或者int4改int8）会重写表&lt;/li&gt;
&lt;li&gt;字段长度增加不会重建索引，一个例外情况是分区表字段长度增加会重建索引（如果这个字段有索引）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;修改字段，参考PostgreSQL学徒。&lt;/p&gt;
&lt;p&gt;这里主要测试&lt;em&gt;分区表将字段改长&lt;/em&gt;的场景，如果存在索引的话，可能会引起分区表上的事务阻塞。
普通表，将有索引的字段改长：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--新建普通表和索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; t111(id int,name varchar(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; t111 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx111 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t111(name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--索引文件relfilenode为417728
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idx111&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_relation_filepath 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417728&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将字段改长
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; t111 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--索引文件relfilenode为417728，未发生变化，普通表索引未重建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idx111&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_relation_filepath 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417728&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;分区表，将有索引的字段改长：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--在分区表上创建一个索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_name &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1(name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看其中一个分区上的索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition1_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dbmgr.lzlpartition1_202301&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Collation&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Nullable&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Default&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Storage&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Stats target &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Description 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; integer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_created &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; now() &lt;span style="color:#f92672"&gt;|&lt;/span&gt; plain &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;: lzlpartition1 &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: ((date_created &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-02-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lzlpartition1_202301_name_idx&amp;#34;&lt;/span&gt; btree (name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Access&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;method&lt;/span&gt;: heap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301_name_idx&amp;#39;&lt;/span&gt;) idx,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301&amp;#39;&lt;/span&gt;) tbl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tbl 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------+-------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417810&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将索引字段改大，分区表索引重建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301_name_idx&amp;#39;&lt;/span&gt;) idx,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301&amp;#39;&lt;/span&gt;) tbl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tbl 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------+-------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417814&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将索引字段改小，分区表重写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;609&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;585&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301_name_idx&amp;#39;&lt;/span&gt;) idx,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301&amp;#39;&lt;/span&gt;) tbl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tbl 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------+-------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417828&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417825&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将索引字段保持原样，分区表索引重建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301_name_idx&amp;#39;&lt;/span&gt;) idx,pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpartition1_202301&amp;#39;&lt;/span&gt;) tbl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tbl 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------+-------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417834&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; base&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16398&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;417825&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;普通表改大字段长度只需要关注统计信息会丢失（int到bigint除外）；但是分区表在改大字段长度时，如果这个字段上有索引，不仅会丢失统计信息，还会重建索引。由于alter修改字段是8级锁，所以重建索引期间会导致长时间阻塞。
建议：先把索引删除，修改完字段后，“父表ONLY+子表CIC+ATTACH”的方式建索引。&lt;/p&gt;

&lt;h3 class="relative group"&gt;分区表维护小结
 &lt;div id="分区表维护小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%bb%b4%e6%8a%a4%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;partition of/drop table/DETACH需要 ACCESS EXCLUSIVE锁；推荐ATTACH/DETACH CONCURRENTLY，它们不会造成阻塞，DETACH CONCURRENTLY需关注已有长事务&lt;/li&gt;
&lt;li&gt;attach表分区前可以提前在分区上创建约束，这样会减去在attach时扫描分区数据的时间&lt;/li&gt;
&lt;li&gt;目前不支持分区表CIC创建索引，可以通过在“主表上only+子表上concurrently+attach索引”的方式创建分区索引，减少业务阻塞时间&lt;/li&gt;
&lt;li&gt;分区表不支持using index方式创建主键&lt;/li&gt;
&lt;li&gt;需要关注分区表修改字段长度这个例外情况&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;分区表的优化
 &lt;div id="分区表的优化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e4%bc%98%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;分区裁剪
 &lt;div id="分区裁剪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a3%81%e5%89%aa" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;分区裁剪（Partition Pruning）可以为声明式分区提升性能，是分区表优化非常重要的特性。如果没有分区裁剪，那么查询会扫描所有分区。当有分区裁剪时，优化器可以通过where条件过滤那些不需要访问的分区



&lt;img src="https://lastdba.com/img/csdn/574daf83f7c1.png" alt="Partition pruning" /&gt;
分区裁剪依赖于分区约束Partition constraint(\d+可以看到），也就是说&lt;strong&gt;查询必须带有分区键&lt;/strong&gt;条件才能进行裁剪。这个约束不同于一般约束constraint，它在分区创建时自动创建。
分区裁剪由enable_partition_pruning参数控制，默认为on。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--没有分区裁剪时，会访问所有分区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_partition_pruning&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--有分区裁剪时，不需要访问的分区被排除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_partition_pruning&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 00:00:00&amp;#39;&lt;/span&gt;::&lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;without&lt;/span&gt; time &lt;span style="color:#66d9ef"&gt;zone&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（官方文档说生成执行计划时发生裁剪，那么explain有Subplans Removed字样，经测试有时候没有，就像上面的explain例子）
&lt;strong&gt;分区裁剪可能发生在两个阶段：生成执行计划时、真正执行时&lt;/strong&gt;
为什么会发生这样的情况呢？因为有时候只有执行时才会知道那些分区可以裁剪。有两种情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Parameterized Nested Loop Joins: The parameter from the outer side of the
join can be used to determine the minimum set of inner side partitions to
scan.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Initplans: Once an initplan has been executed we can then determine which
partitions match the value from the initplan.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;模拟执行时发生裁剪：从其他表拿数据优化器肯定不知道数据是什么，就无法以此为依据在执行计划时发生分区裁剪：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--创建一个其他表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; x(date_created &lt;span style="color:#66d9ef"&gt;timestamp&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; x &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01 09:00:00&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--仅生成执行计划，不执行，没有发生裁剪
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; date_created &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; x);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1904&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;68&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1904&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InitPlan &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;returns&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; x (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2260&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--执行sql，发生裁剪。关键字never executed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; date_created &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; x);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1904&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;68&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1904&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;680&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;682&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InitPlan &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;returns&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; x (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2260&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;013&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;014&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;029&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;676&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;008&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;652&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; loops&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Rows&lt;/span&gt; Removed &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; Filter: &lt;span style="color:#ae81ff"&gt;45382&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) (never executed)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) (never executed)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;157&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Execution Time: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;732&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;partition wise join
 &lt;div id="partition-wise-join" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#partition-wise-join" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;partition wise join可以减少分区连接的代价。
假设有两个分区表t1、t2，他们都有3个分区(p1,p2,p3)且分区定义一致，t1的每个分区10条数据，t2的每个分区20条数据：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;t1&lt;/th&gt;
 &lt;th&gt;t2&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;p1&lt;/td&gt;
 &lt;td&gt;10 rows&lt;/td&gt;
 &lt;td&gt;20 rows&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;p2&lt;/td&gt;
 &lt;td&gt;10 rows&lt;/td&gt;
 &lt;td&gt;20 rows&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;p3&lt;/td&gt;
 &lt;td&gt;10 rows&lt;/td&gt;
 &lt;td&gt;20 rows&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;此时t1和t2表进行连接，&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;正常情况下需要把所有两个分区数据取出进行连接，他们的行的连接比较次数为：
(10+10+10)*(20+20+20)=180次&lt;/li&gt;
&lt;li&gt;有partition wise join的情况下，因为结构差不多，只需要连接对应的分区，如
t1.p1&amp;lt;=&amp;gt;t2.p1，
t1.p2&amp;lt;=&amp;gt;t2.p2，
t1.p3&amp;lt;=&amp;gt;t2.p3，
此时的连接比较次数为：
(10*20)*3=90次&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在分区特别多的情况下，partition wise join的代价会小很多。
参数&lt;code&gt;enable_partitionwise_join&lt;/code&gt;：是否开启partition wise join，默认关闭&lt;/p&gt;
&lt;p&gt;partition wise join的前提条件非常苛刻：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接条件必须包含分区键&lt;/li&gt;
&lt;li&gt;分区键必须是相同的数据类型&lt;/li&gt;
&lt;li&gt;分区必须一一对应&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看上去条件苛刻，两个不同的用途的表能产生partition wise join的情况是也是比较少的，比较常见的应该是两个表都是range时间分区。还有一种情况，如果是分区表自我连接，也符合partition wise join的前提：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--未开启partition wise join的情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; p1.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;,p2.name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 p1,lzlpartition1 p2 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p1.date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;p2.date_created &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; p2.name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;546&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;9256&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;182252&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;288&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (p1.date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; p2.date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2085&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;85364&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 p1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 p1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 p1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;541&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;541&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;427&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;541&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;427&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 p2_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;284&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 p2_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;95&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;248&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 p2_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--开启partition wise join的情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_partitionwise_join &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; p1.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;,p2.name &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 p1,lzlpartition1 p2 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p1.date_created&lt;span style="color:#f92672"&gt;=&lt;/span&gt;p2.date_created &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; p2.name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;287&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2529&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;83&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;438&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;288&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;287&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1338&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;232&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;288&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (p1_1.date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; p2_1.date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 p1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;284&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;284&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 p2_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;284&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;99&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1166&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;202&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;288&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (p1_2.date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; p2_2.date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 p1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;248&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;248&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 p2_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;95&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;248&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;288&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (p1_3.date_created &lt;span style="color:#f92672"&gt;=&lt;/span&gt; p2_3.date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 p1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Hash (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 p2_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;146&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304_name_idx (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((name)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在没有开启partition wise join的情况下，优化器需要先访问分区表p2的所有分区数据（符合条件的）放一起(append)，然后与分区表p1的所有分区数据通过分区键连接(Hash Join)。
在开启partition wise join的情况下，优化器将p1、p2两个分区表（实际上是一个，访问了两次）所对应的分区相连接：
p1_1&amp;lt;=&amp;gt;p2_1 Hash Join
p1_2&amp;lt;=&amp;gt;p2_2 Hash Join
p1_3&amp;lt;=&amp;gt;p2_3 Hash Join
然后再把数据合到一起（append）。
如果数据分区足够多，再加上分区裁剪，partition wise join会有很好的优化效果。&lt;/p&gt;

&lt;h3 class="relative group"&gt;partition wise grouping/aggregation
 &lt;div id="partition-wise-groupingaggregation" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#partition-wise-groupingaggregation" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;分区表在进行分区数据聚合计算时，分区可以各自算各自的，不需要扫描所有分区数据进行聚合计算，只需要各自分区的数据聚合计算完成后汇总返回即可。
没有partition wise grouping本质上是“&lt;strong&gt;先扫描所有分区，再聚合计算&lt;/strong&gt;”；有partition wise grouping是“&lt;strong&gt;先分区聚合计算，再汇合数据&lt;/strong&gt;”。&lt;/p&gt;
&lt;p&gt;partition wise grouping的优势如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分区在foreign server时，可以将聚合算子下推到foreign server&lt;/li&gt;
&lt;li&gt;聚合到hash表时，每个分区而不是所有分区去使用内存hash表的空间，可以减少内存使用&lt;/li&gt;
&lt;li&gt;聚合算法下方到各自的分区可以更好的使用索引、并行等等特性&lt;/li&gt;
&lt;li&gt;更少的数据对比。虽然数据扫描都是一样的，但是减少了数据对比，比如最后一个分区的数据不需要与第一个分区的数据进行对比&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参数&lt;code&gt;enable_partitionwise_aggregate&lt;/code&gt;：是否开启partition wise grouping/aggregation，默认关闭&lt;/p&gt;
&lt;p&gt;partition wise aggregate示例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;vacuum&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;) lzlpartition1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--未开启wise agg
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_partitionwise_aggregate &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; date_created,&lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(id),&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; date_created &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10354&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10562&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;89&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;83180&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.date_created, (&lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(lzlpartition1.id)), (&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2725&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3557&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;83180&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.date_created
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2085&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;85364&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_3 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--开启wise agg
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_partitionwise_aggregate &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; date_created,&lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(id),&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; date_created &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10356&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10564&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;83296&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.date_created, (&lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(lzlpartition1.id)), (&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1219&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3548&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;83296&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1219&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1663&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;44387&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.date_created
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1061&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;77&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1448&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;38709&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1_1.date_created
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1_2.date_created
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;无wise aggregate时，先扫描所有数据再合并（Append），合并后再聚合计算（HashAggregate）；
partition wise aggregate先在分区聚合计算（HashAggregate），然后在合并结果（Append）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;partial aggregation&lt;/strong&gt;
聚合算法可以下放到分区上进行计算，此时聚合后的数据分为两种情况：聚合数据不重复（group包含分区键），聚合数据有重复（group不包含分区键）。
当聚合数据不重复时，只需要把各自分区算出来的聚合数据简单的加到一起（append）即可（就像上面的案例）；当各自分区算出来的聚合数据重复时，仍然需要再聚合计算一次（Finalize Aggregate）。不包含分区键的聚合计算就是partial aggregation。&lt;/p&gt;
&lt;p&gt;partial aggregation示例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--group by不是分区键时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; enable_partitionwise_aggregate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; enable_partitionwise_aggregate 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id,&lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1 &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; id ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Finalize HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2474&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2573&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9900&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1105&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;76&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2377&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;47&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19467&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1105&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;76&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1202&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9652&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1.id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;962&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;95&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1059&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9615&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1_1.id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; HashAggregate (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;75&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;75&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: lzlpartition1_2.id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;group by不包含分区键，也可以进行聚合计算，但是必须在稍后总聚合Finalize HashAggregate&lt;/p&gt;
&lt;p&gt;即使没有group by，也可能发生Partial Aggregate：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; enable_partitionwise_aggregate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; enable_partitionwise_aggregate 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Finalize &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;max&lt;/span&gt;(date_created) &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QUERY PLAN 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Finalize &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1872&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;992&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202301 lzlpartition1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45384&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;864&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202302 lzlpartition1_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;765&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;39530&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition1_202304 lzlpartition1_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;触发Partial Aggregate的前提不是group。应从Partial Aggregate的目的去考虑，它的目的是把聚合下放到分区，那么没有group的聚合其实也可以这么做，就像上面两个例子：他们都是在分区上聚合计算后（Partial Aggregate），汇总到一起再聚合计算一次（ Finalize Aggregate）；如果没有打开参数，这些聚合发生在扫描完所有分区后。&lt;/p&gt;

&lt;h2 class="relative group"&gt;分区表的历史
 &lt;div id="分区表的历史" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e5%8e%86%e5%8f%b2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;声明式分区经过了多个版本的增强，如今已非常成熟。对于历史版本的声明式分区，功能增强如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PG9.6以前&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只能继承表实现分区功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG10&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持声明式分区&lt;/li&gt;
&lt;li&gt;支持range、list分区&lt;/li&gt;
&lt;li&gt;支持attach/detach表分区&lt;/li&gt;
&lt;li&gt;支持分区裁剪&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG11&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加支持HASH分区&lt;/li&gt;
&lt;li&gt;支持创建主键、外键、索引、触发器&lt;/li&gt;
&lt;li&gt;支持update分区键、自动创建分区上的索引&lt;/li&gt;
&lt;li&gt;支持default分区&lt;/li&gt;
&lt;li&gt;支持attach索引&lt;/li&gt;
&lt;li&gt;支持FOR EACH ROW触发器，自动在已有/未来的子分区上创建&lt;/li&gt;
&lt;li&gt;新增enable_partition_pruning参数；裁剪增强&lt;/li&gt;
&lt;li&gt;支持partition wise join&lt;/li&gt;
&lt;li&gt;支持partition wise aggregation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG12&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强查询、插入、pruning、COPY性能&lt;/li&gt;
&lt;li&gt;支持外键约束to分区表&lt;/li&gt;
&lt;li&gt;支持非阻塞分区表ATTACH:&lt;code&gt;ALTER TABLE ATTACH PARTITION&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG13&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强pruning&lt;/li&gt;
&lt;li&gt;增强partition wise join&lt;/li&gt;
&lt;li&gt;支持BEFORE triggers&lt;/li&gt;
&lt;li&gt;支持发布分区表；支持订阅写入分区表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG14&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强update、delete性能&lt;/li&gt;
&lt;li&gt;支持非阻塞分区表DETACH：&lt;code&gt;ALTER TABLE ... DETACH PARTITION ... CONCURRENTLY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;支持reindex分区表的索引&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG15&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强执行计划生成，减少多分区时执行计划生成时间&lt;/li&gt;
&lt;li&gt;增强排序&lt;/li&gt;
&lt;li&gt;支持cluster分区表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG16&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强generated列的限制，主表有generated列子分区也必须包含。&lt;/li&gt;
&lt;li&gt;增强查找range、list分区&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;参考
 &lt;div id="参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《PostgreSQL修炼之道》&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/NW8XOZNq0YlDZvx24H737Q" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/NW8XOZNq0YlDZvx24H737Q&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/ddl-partitioning.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/ddl-partitioning.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/ddl-inherit.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/ddl-inherit.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/13/sql-altertable.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/sql-altertable.html&lt;/a&gt;
&lt;a href="https://github.com/postgrespro/pg_pathman" target="_blank" rel="noreferrer"&gt;https://github.com/postgrespro/pg_pathman&lt;/a&gt;
&lt;a href="https://developer.aliyun.com/article/62314" target="_blank" rel="noreferrer"&gt;https://developer.aliyun.com/article/62314&lt;/a&gt;
&lt;a href="https://hevodata.com/learn/postgresql-partitions" target="_blank" rel="noreferrer"&gt;https://hevodata.com/learn/postgresql-partitions&lt;/a&gt;
&lt;a href="https://www.postgresql.fastware.com/postgresql-insider-prt-ove" target="_blank" rel="noreferrer"&gt;https://www.postgresql.fastware.com/postgresql-insider-prt-ove&lt;/a&gt;
&lt;a href="https://www.buckenhofer.com/2021/01/postgresql-partitioning-guide/" target="_blank" rel="noreferrer"&gt;https://www.buckenhofer.com/2021/01/postgresql-partitioning-guide/&lt;/a&gt;
&lt;a href="https://www.depesz.com/2018/05/01/waiting-for-postgresql-11-support-partition-pruning-at-execution-time/" target="_blank" rel="noreferrer"&gt;https://www.depesz.com/2018/05/01/waiting-for-postgresql-11-support-partition-pruning-at-execution-time/&lt;/a&gt;
&lt;a href="https://blog.csdn.net/horses/article/details/86164273" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/horses/article/details/86164273&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pgsql.tech/article_0_10000102" target="_blank" rel="noreferrer"&gt;http://www.pgsql.tech/article_0_10000102&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://brandur.org/fragments/postgres-partitioning-2022" target="_blank" rel="noreferrer"&gt;https://brandur.org/fragments/postgres-partitioning-2022&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL内存浅析</title><link>https://lastdba.com/2024/08/12/postgresql%E5%86%85%E5%AD%98%E6%B5%85%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql%E5%86%85%E5%AD%98%E6%B5%85%E6%9E%90/</guid><description>&lt;h2 class="relative group"&gt;体系结构
 &lt;div id="体系结构" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bd%93%e7%b3%bb%e7%bb%93%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8ca0ab97a875.png" alt="Shared Memory in PostgreSQL" /&gt;
（https://www.postgresql.fastware.com/blog/lets-get-back-to-basics-postgresql-memory-components）&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;体系结构
 &lt;div id="体系结构" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bd%93%e7%b3%bb%e7%bb%93%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8ca0ab97a875.png" alt="Shared Memory in PostgreSQL" /&gt;
（https://www.postgresql.fastware.com/blog/lets-get-back-to-basics-postgresql-memory-components）&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6ec5a1dae77e.png" alt="PostgreSQL进程结构和内存结构 - 图2" /&gt;
（http://geekdaxue.co/read/fcant@sql/qts5is)&lt;/p&gt;

&lt;h2 class="relative group"&gt;共享内存
 &lt;div id="共享内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;linux的共享内存实现
 &lt;div id="linux的共享内存实现" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#linux%e7%9a%84%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98%e5%ae%9e%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/026fc1403eb5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://momjian.us/main/writings/pgsql/inside_shmem.pdf" target="_blank" rel="noreferrer"&gt;https://momjian.us/main/writings/pgsql/inside_shmem.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;linux上的共享内存&lt;/strong&gt;
共享内存是基于 Unix 的操作系统（包括 Linux）支持的 IPC（进程间通信）机制。它是一种内存类型，多个进程可以同时使用它们来相互通信。共享内存是最快的IPC（inter-process communication)机制之一，因为它不需要进程间相互copy数据。进程可以通过自己的地址空间访问到共享内存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;共享内存的两种形式&lt;/strong&gt;
共享内存的一种形式是内存映射文件。一旦多个进程将同一文件映射到其地址空间，它们就可以访问文件的内容，并直接使用映射的内存同时更新文件。共享内存的另一种形式是匿名内存。它是指程序分配的共享内存区域，而不将其与文件或持久存储机制相关联。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;mmap()&lt;/strong&gt;
map file 到一个进程的地址空间使用的是&lt;code&gt;mmap()&lt;/code&gt;，匿名内存也可以用&lt;code&gt;mmap()&lt;/code&gt;。&lt;a href="https://www.man7.org/linux/man-pages/man2/mmap.2.html" target="_blank" rel="noreferrer"&gt;mmap&lt;/a&gt;是标准C库里的。匿名内存使用的flag应是&lt;code&gt;MAP_ANONYMOUS&lt;/code&gt; or&lt;code&gt;MAP_ANON&lt;/code&gt;，此时&lt;code&gt;fd&lt;/code&gt;为空或者-1，&lt;code&gt;offset&lt;/code&gt;应该为0。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fcd702da523d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.tutorialsdaddy.com/courses/linux-device-driver/lessons/mmap/" target="_blank" rel="noreferrer"&gt;http://www.tutorialsdaddy.com/courses/linux-device-driver/lessons/mmap/&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg中的共享内存
 &lt;div id="pg中的共享内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e4%b8%ad%e7%9a%84%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0a37e863fe80.png" alt="在这里插入图片描述" /&gt;
&lt;a href="https://www.interdb.jp/pg/pgsql02.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql02.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pg中有许多共享内存：shared buffers、wal buffer、clog buffer、lock space等&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;shared buffer&lt;/strong&gt;
pg缓存数据的共享内存区，类似oracle的SGA。当数据命中shared buffer时，直接从内存中读取而不需要发生磁盘IO。
PostgreSQL 将表中的页面和索引从持久存储加载到该区域，并直接操作它们。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;wal buffer&lt;/strong&gt;
为确保服务器故障不会丢失任何数据，PostgreSQL 支持 WAL 机制。WAL 数据（也称为 XLOG 记录）是 PostgreSQL 中的事务日志。WAL BUFFER是写入持久性存储之前 WAL 数据的缓冲区。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CLOG BUFFER&lt;/strong&gt;
提交日志 （CLOG） 为并发控制机制保留所有事务（例如，in_progress、已提交、已中止）的状态。	相应的CLOG BUFFER是CLOG写入磁盘前的缓冲区。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg的共享内存相关参数
 &lt;div id="pg的共享内存相关参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e7%9a%84%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98%e7%9b%b8%e5%85%b3%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;shared_buffers&lt;/code&gt;&lt;/strong&gt;
默认128M，建议配置为25%总内存。因为PostgreSQL的私有内存一般会占的比较多，而且依赖cache，必须给OS留足内存，所以不建议像oracle那样把SGA调到一个比较大的值（相对总内存来说）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;shared_memory_type&lt;/code&gt;&lt;/strong&gt;
指定共享内存的实现方法，不仅是shared_buffer也包含其他共享数据的区域。
共享内存的实现方式因平台而不同，（看上去）linux的默认为&lt;code&gt;mmap&lt;/code&gt;。其他值有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;posix&lt;/code&gt; (for POSIX shared memory allocated using &lt;code&gt;shm_open&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sysv&lt;/code&gt; (for System V shared memory allocated via &lt;code&gt;shmget&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;windows&lt;/code&gt; (for Windows shared memory)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mmap&lt;/code&gt; (to simulate shared memory using memory-mapped files stored in the data directory)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;默认情况下，PostgreSQL使用极少量的System V共享内存，绝大部分都是mmap共享内存。由于&lt;a href="https://postgreshelp.com/postgresql-dynamic-shared-memory-posix-vs-mmap/" target="_blank" rel="noreferrer"&gt;POSIX和System V的IPC区别&lt;/a&gt;，信号实现不同，可显式将&lt;code&gt;shared_memory_type&lt;/code&gt;参数调整IPC实现机制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/kernel-resources.html#SYSVIPC" target="_blank" rel="noreferrer"&gt;设置system V IPC&lt;/a&gt;（默认是&lt;code&gt;mmap&lt;/code&gt;）：
在Linux和FreeBSD系统中默认共享内存系统设置一般足够了，&lt;code&gt;shared_memory_type&lt;/code&gt;设置为&lt;code&gt;sysv&lt;/code&gt;在这2个系统上也不生效（System V semaphores are not used on this platform）。
OpenBSD系统上，如果将&lt;code&gt;shared_memory_type&lt;/code&gt;设置为&lt;code&gt;sysv&lt;/code&gt;，默认的共享内存系统参数就不够，需要通过sysctl调整。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设置POSIX IPC：
POSIX semaphores在Linux和FreeBSD上有效。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;dynamic_shared_memory_type&lt;/code&gt;&lt;/strong&gt;
动态共享内存的机制，默认为posix，该参数对并行查询很重要。&lt;a href="https://www.postgresql.org/message-id/CA%2BhUKGJOj7qzDLxeFPVvto8YEWop6FSQoTYPO9Z6Ee%3Di-nPS_Q%40mail.gmail.com" target="_blank" rel="noreferrer"&gt;关于/dev/shm的社区邮件&lt;/a&gt;描述：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PostgreSQL creates segments in /dev/shm for parallel queries (via&lt;br&gt;
shm_open()), not for shared buffers. The amount used is controlled by&lt;br&gt;
work_mem. Queries can use up to work_mem for each node you see in the&lt;br&gt;
EXPLAIN plan, and for each process, so it can be quite a lot if you&lt;br&gt;
have lots of parallel worker processes and/or lots of&lt;br&gt;
tables/partitions being sorted or hashed in your query.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;翻译：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并行查询用的是POSIX，会在&lt;code&gt;/dev/shm&lt;/code&gt;创建segment&lt;/li&gt;
&lt;li&gt;并行查询不是使用的&lt;code&gt;shared buffers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每个查询的plan node由&lt;code&gt;work_mem&lt;/code&gt;限制！&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;min_dynamic_shared_memory&lt;/code&gt;&lt;/strong&gt;
被并行查询使用的内存初始大小，在server启动时分配，与&lt;code&gt;huge_pages&lt;/code&gt;，&lt;code&gt;dynamic_shared_memory_type&lt;/code&gt;相关&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;huge_pages&lt;/code&gt;&lt;/strong&gt;
该参数控制&lt;strong&gt;主共享内存区&lt;/strong&gt;是否使用大页，也就是说私有内存、操作上的内存不受这个限制。pg使用大页目前只支持linux和windows系统；在linux系统中，只支持&lt;code&gt;shared_memory_type&lt;/code&gt;设置为&lt;code&gt;mmap&lt;/code&gt;时！&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;可用设置&lt;/th&gt;
 &lt;th&gt;描述&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;try&lt;/td&gt;
 &lt;td&gt;default, 尝试申请大页&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;on&lt;/td&gt;
 &lt;td&gt;用大页内存，没申请到大页不会启动server&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;off&lt;/td&gt;
 &lt;td&gt;不使用大页&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;huge_page_size&lt;/code&gt;&lt;/strong&gt;
控制大页的大小。默认为0，表示pg使用的是操作系统提供的大页大小。只在linux上支持设置非默认值。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg_shmem_allocations视图
 &lt;div id="pg_shmem_allocations视图" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_shmem_allocations%e8%a7%86%e5%9b%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg_shmem_allocations是pg13开始提供的视图，可查看主要的共享内存段的分配情况，包括postgres本身和插件的。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sum&lt;/span&gt;(allocated_size)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt; gb &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_shmem_allocations;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gb 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;7658920288085938&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_shmem_allocations &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;desc&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;size&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; allocated_size 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------------------+------------+------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffer Blocks &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;38575360&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2415919104&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2415919104&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2729553280&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;240300672&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;240300672&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;anonymous&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;240198528&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;240198528&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffer Descriptors &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19700992&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18874368&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18874368&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; XLOG Ctl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;171008&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16803472&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16803584&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Backend Activity Buffer &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2707733248&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10680320&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10680320&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;NULL表示未使用的内存，anonymous表示匿名页的分配
pg_shmem_allocations视图的大部分内存模块都挺难理解的，直接搜源码也能找到，不过没有一个直观的解释，只是把源码相关init内存模块的数据展示出来。&lt;/p&gt;
&lt;p&gt;示例buffer blocks：
直接源码搜索“buffer blocks”：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//初始化shared buffer pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//只调用一次，在shared memory初始化时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;InitBufferPool&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		foundBufs,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				foundDescs,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				foundIOCV,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				foundBufCkpt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Align descriptors to a cacheline boundary. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BufferDescriptors &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (BufferDescPadded &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ShmemInitStruct&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Buffer Descriptors&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						NBuffers &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(BufferDescPadded),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;foundDescs);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BufferBlocks &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ShmemInitStruct&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Buffer Blocks&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						NBuffers &lt;span style="color:#f92672"&gt;*&lt;/span&gt; (Size) BLCKSZ, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;foundBufs);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Align condition variables to cacheline boundary. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BufferIOCVArray &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (ConditionVariableMinimallyPadded &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ShmemInitStruct&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Buffer IO Condition Variables&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						NBuffers &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(ConditionVariableMinimallyPadded),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;foundIOCV);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Checkpoint BufferIds是用来在shared memory中排序checkpoint的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CkptBufferIds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (CkptSortItem &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ShmemInitStruct&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Checkpoint BufferIds&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						NBuffers &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(CkptSortItem), &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;foundBufCkpt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;InitBufferPool()函数是初始化shared buffer的&lt;/li&gt;
&lt;li&gt;shared buffer有4个子池：Buffer Descriptors，Buffer Blocks，Buffer IO Condition Variables，Checkpoint BufferIds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​&lt;/p&gt;

&lt;h2 class="relative group"&gt;私有内存
 &lt;div id="私有内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%a7%81%e6%9c%89%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;私有内存是pg为每个session或进程分配的内存区域，它们通常不像shared buffer那样只有一个。每个进程的私有内存是不能相互访问的。



&lt;img src="https://lastdba.com/img/csdn/b9b739d63ed8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;temp_buffers&lt;/code&gt;&lt;/strong&gt;
temp buffer用于缓存临时表数据，默认8m。temp_buffers是私有内存，所以临时表只能当前session可见。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;work_mem&lt;/code&gt;&lt;/strong&gt;
查询操作（query operation）所使用的最大内存，如排序、hash表，默认4m。
&lt;em&gt;each query or each plan node？&lt;/em&gt;
&lt;a href="https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM" target="_blank" rel="noreferrer"&gt;官方文档&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Note that a complex query might perform several sort and hash operations at the same time, with each operation generally being allowed to use as much memory as this value specifies before it starts to write data into temporary files.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/CA%2BhUKGJOj7qzDLxeFPVvto8YEWop6FSQoTYPO9Z6Ee%3Di-nPS_Q%40mail.gmail.com" target="_blank" rel="noreferrer"&gt;关于/dev/shm的社区邮件&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Queries can use up to work_mem for each node you see in the&lt;br&gt;
EXPLAIN plan,&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;em&gt;该参数是针对查询中的每个operation(plan node)，而不是each query&lt;/em&gt;。一个query可以有很多并行的operation，所以一个查询也可能占用很多内存。所以work_mem的设置需要很谨慎，不能设置的过高导致操作系统内存被耗尽，如最坏的情况：多个会话、会话有多个plan node、plan node使用的大量消耗work mem的operation。
&lt;em&gt;哪些operation会使用到work mem？：&lt;/em&gt;
对于sort操作有：ORDER BY、DISTINCT、merge joins；对于使用hash表有： hash joins、hash-based aggregation、memoize nodes、基于hash的in子查询&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hash_mem_multiplier&lt;/code&gt;&lt;/strong&gt;
用于限制基于hash-based operations的内存大小，限制是&lt;code&gt;hash_mem_multiplier&lt;/code&gt;*&lt;code&gt;work mem&lt;/code&gt;。&lt;code&gt;hash_mem_multiplier&lt;/code&gt;默认为2。
虽然可以限制work mem，但是无法限制query使用了多少个hash操作，所以pg13增加了这个参数。也就是说12（含）以前，是很难限制hash table的内存的。
&lt;em&gt;我们在9.6的生产环境中找到消耗300G内存的一个会话，罪魁祸首就是低版本没有hash table限制和执行计划错误的使用hash table&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;maintenance_work_mem&lt;/code&gt;&lt;/strong&gt;
&lt;code&gt;VACUUM&lt;/code&gt;, &lt;code&gt;CREATE INDEX&lt;/code&gt;, and &lt;code&gt;ALTER TABLE ADD FOREIGN KEY&lt;/code&gt;等操作使用的内存区域，这些都是会话发起的操作，有独立的进程，使用私有内存。在一个会话中这些maintenance操作是不能并行的，而且一把并发量也不高，所以这个参数可以调整比较大。
autovacuum也可能用到这个内存区域和限制，参考&lt;code&gt;autovacuum_work_mem&lt;/code&gt;解释&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;autovacuum_work_mem&lt;/code&gt;&lt;/strong&gt;
每个autovacuum worker process使用的最大内存，默认-1，表示使用&lt;code&gt;maintenance_work_mem&lt;/code&gt;参数来限制autovacuum worker。vacuum最多使用1GB的内存，autovacuum同样是这个限制，所以vacuum/autovacuumd的内存限制设置到超过1G没有意义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;vacuum_buffer_usage_limit&lt;/code&gt;&lt;/strong&gt;
限制&lt;code&gt;VACUUM&lt;/code&gt;、&lt;code&gt;ANALYZE&lt;/code&gt;从共享内存中访问的page数，以防太多的page被evict。default为256kb，0表示没有限制。
在使用&lt;code&gt;VACUUM&lt;/code&gt;、&lt;code&gt;ANALYZE&lt;/code&gt;命令时可指定&lt;code&gt;BUFFER_USAGE_LIMIT&lt;/code&gt;，此时的设置优先级高于GUI参数&lt;code&gt;vacuum_buffer_usage_limit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;max_stack_depth&lt;/code&gt;&lt;/strong&gt;
执行堆栈的最大安全深度，一般意味着单个backend进程上执行一个递归函数的堆栈深度。默认为2MB。操作系统kernel stack limit应设置的比这个&lt;code&gt;max_stack_depth&lt;/code&gt;大一点。
递归函数超过堆栈深度会报如下错误：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: stack depth limit exceeded HINT: 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Increase the configuration parameter max_stack_depth &lt;span style="color:#f92672"&gt;(&lt;/span&gt;currently 2048kB&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;after ensuring the platform’s stack depth limit is adequate.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;&lt;/strong&gt;
pg13以前，逻辑解析最多会在内存中保留4096条变更（&lt;code&gt;max_changes_in_memory&lt;/code&gt;代码中写死）。pg13引入参数&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;，如果逻辑解析持有的数据大过这个内存值，会写入磁盘。默认64MB。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;each replication connection only uses a single buffer of this size,&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;一般来说逻辑复制链路不会很多，所以&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;设置大一点也没有关系&lt;/p&gt;

&lt;h2 class="relative group"&gt;xxCache
 &lt;div id="xxcache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#xxcache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;xxCache也是私有内存&lt;/strong&gt;，例如pg会将relation的元数据缓存到relcache。在官方文档中相关描述比较少，但是PG的内存问题往往跟这个相关。
例如catalog cache导致每个backend process都占用了很多内存而且不释放的问题，在许多环境中都出现了。这里是2016年德哥提的&lt;a href="https://www.postgresql.org/message-id/flat/20160708012833.1419.89062%40wrigleys.postgresql.org#20160708012833.1419.89062@wrigleys.postgresql.org" target="_blank" rel="noreferrer"&gt;关于catalog cache占用较多内存的社区邮件&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Every PostgreSQL session holds system data in own cache. Usually this cache is pretty small (for significant numbers of users). But can be pretty big if your catalog is untypically big and you touch almost all objects from&lt;br&gt;
catalog in session. A implementation of this cache is simple - there is not&lt;br&gt;
delete or limits. There is not garabage collector (and issue related to&lt;br&gt;
GC), what is great, but the long sessions on big catalog can be problem.&lt;br&gt;
The solution is simple - close session over some time or over some number of operations. Then all memory in caches will be released.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;社区对于catalog cache解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个会话都有自己的cache缓存系统数据（元数据等）&lt;/li&gt;
&lt;li&gt;一般这个cache很小。当catalog很大且会话访问过所有catalog时，cache会变的很大&lt;/li&gt;
&lt;li&gt;cache的管理很简单，&lt;strong&gt;没有删除机制和limit限制&lt;/strong&gt;（其实有invalidation消息）&lt;/li&gt;
&lt;li&gt;关闭会话会释放cache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tom Lane大佬的解决方案也是简单粗暴——加硬件资源：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I do not think you should complain if that takes a great deal of memory.Either rethink why you need so many tables, or buy hardware commensurate with the size of your problem.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;其实cache也有很多知识点需要关注，了解其原理后cache导致的内存问题解决办法可能不只是一种。
xxCache有很多种类，如relcache、syscache、plancache等等。由于资料比较少，理解xxcache只有翻看源码了。xxCache主要源码都在&lt;code&gt;src/backend/utils/cache&lt;/code&gt;下。
&lt;em&gt;源码结构&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;inval.c				&lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;私有&lt;/span&gt;cache的invalidation消息分发器&lt;span style="color:#960050;background-color:#1e0010"&gt;。对应的&lt;/span&gt;share cache的invalidation消息处理为sinval.c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relfilenodemap.c	&lt;span style="color:#f92672"&gt;--&lt;/span&gt;relfilenode to oid mapping cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ts_cache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;Tsearch&lt;span style="color:#960050;background-color:#1e0010"&gt;（文本搜索）相关对象的&lt;/span&gt;cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relmapper.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;catalog to relfilenode mapping cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;typcache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;type cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spccache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;tablespace cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;evtcache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;event trigger cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;attoptcache.c		&lt;span style="color:#f92672"&gt;--&lt;/span&gt;attribute cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plancache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;plan cache 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relcache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;relation cache 							 							&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;本次重点&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;catcache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;system catalog cache 					 					&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;本次重点&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;syscache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;在&lt;/span&gt;catcache上一层&lt;span style="color:#960050;background-color:#1e0010"&gt;，也是&lt;/span&gt;system catalog cache	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;本次重点&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lsyscache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;为了方便查询&lt;/span&gt;catalog cache的routines&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;l应该指lookup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;partcache.c			&lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;操作在&lt;/span&gt;relcache中的分区信息的routines&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;处理各类cache外，还包含一些操作、消息的源码。下面重点关注的是relcache、catcache/syscache和invalidation消息。&lt;/p&gt;

&lt;h3 class="relative group"&gt;relcache
 &lt;div id="relcache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#relcache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;relcache条目数据保存了什么？&lt;/strong&gt;
在&lt;code&gt;src/include/utils/rel.h&lt;/code&gt;中定义relcache的条目：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; POSTGRES relation &lt;span style="color:#a6e22e"&gt;descriptor&lt;/span&gt; (a&lt;span style="color:#f92672"&gt;/&lt;/span&gt;k&lt;span style="color:#f92672"&gt;/&lt;/span&gt;a relcache entry) definitions.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中&lt;code&gt;RelationData&lt;/code&gt;是relcache条目最主要的数据结构：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; RelationData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RelFileNode rd_node;		&lt;span style="color:#75715e"&gt;/* relation的物理标识 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SMgrRelation rd_smgr;		&lt;span style="color:#75715e"&gt;/* 缓存的文件句柄，没有则为NULL, or NULL */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			rd_refcnt;		&lt;span style="color:#75715e"&gt;/* reference count */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BackendId	rd_backend;		&lt;span style="color:#75715e"&gt;/* 如果是临时relation，它的所有者backend id */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_islocaltemp; &lt;span style="color:#75715e"&gt;/* 是不是当前会话的temp rel */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_isnailed;	&lt;span style="color:#75715e"&gt;/* 是否已经nail再cache中 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_isvalid;		&lt;span style="color:#75715e"&gt;/* relcache条目是否有效 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_indexvalid;	&lt;span style="color:#75715e"&gt;/* relation上的索引是否有效 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_statvalid;	&lt;span style="color:#75715e"&gt;/* relation上的统计信息是否有效 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 一些子事务信息 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SubTransactionId rd_createSubid;	&lt;span style="color:#75715e"&gt;/* rel was created in current xact */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SubTransactionId rd_newRelfilenodeSubid;	&lt;span style="color:#75715e"&gt;/* highest subxact changing rd_node to current value */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SubTransactionId rd_firstRelfilenodeSubid;	&lt;span style="color:#75715e"&gt;/* highest subxact changing rd_node to any value */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SubTransactionId rd_droppedSubid;	&lt;span style="color:#75715e"&gt;/* dropped with another Subid set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Form_pg_class rd_rel;		&lt;span style="color:#75715e"&gt;/* RELATION的在pg_class上的元组指针 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TupleDesc	rd_att;			&lt;span style="color:#75715e"&gt;/* 元组的描述信息 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			rd_id;			&lt;span style="color:#75715e"&gt;/* relation的oid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	LockInfoData rd_lockInfo;	&lt;span style="color:#75715e"&gt;/* relation上的锁信息 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RuleLock &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_rules;		&lt;span style="color:#75715e"&gt;/* rewrite rules */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext rd_rulescxt;	&lt;span style="color:#75715e"&gt;/* rd_rules的私有memory cxt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TriggerDesc &lt;span style="color:#f92672"&gt;*&lt;/span&gt;trigdesc;		&lt;span style="color:#75715e"&gt;/* 触发器信息，rel上没有为NULL */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 外键信息 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	List	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_fkeylist;	&lt;span style="color:#75715e"&gt;/* list of ForeignKeyCacheInfo (see below) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		rd_fkeyvalid;	&lt;span style="color:#75715e"&gt;/* true if list has been computed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 分区信息 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PartitionKey rd_partkey;	&lt;span style="color:#75715e"&gt;/* partition key, or NULL */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext rd_partkeycxt;	&lt;span style="color:#75715e"&gt;/* private context for rd_partkey, if any */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	List	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_indexlist;	&lt;span style="color:#75715e"&gt;/* 所有索引的OID列表 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			rd_pkindex;		&lt;span style="color:#75715e"&gt;/* 主键的oid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			rd_replidindex; &lt;span style="color:#75715e"&gt;/* replica identity index的oid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	List	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_statlist;	&lt;span style="color:#75715e"&gt;/* extended stats的oid列表 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PublicationDesc &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_pubdesc;	&lt;span style="color:#75715e"&gt;/* publication descriptor, or NULL */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	bytea	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_options;		&lt;span style="color:#75715e"&gt;/* parsed pg_class.reloptions */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Form_pg_index rd_index;		&lt;span style="color:#75715e"&gt;/* 索引在pg_index元组的描述 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; HeapTupleData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_indextuple;	&lt;span style="color:#75715e"&gt;/* 所有pg_index元组 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext rd_indexcxt;	&lt;span style="color:#75715e"&gt;/* index的cxt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_amcache;		&lt;span style="color:#75715e"&gt;/* available for use by index/table AM */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; FdwRoutine &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rd_fdwroutine;	&lt;span style="color:#75715e"&gt;/* cached function pointers, or NULL */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} RelationData;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RelationData&lt;/code&gt;包含了非常多的relation相关的元数据：oid、pg_class、分区表、子事务、行安全策略、统计信息、索引元数据、am等等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;relcache的ROUTINES&lt;/strong&gt;
ROUTINES源码位于&lt;code&gt;src/backend/utils/cache/relcache.c&lt;/code&gt;
主要有5个阶段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RelationCacheInitialize&lt;/code&gt; - 初始化relcache，初始化为空的&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RelationCacheInitializePhase2&lt;/code&gt; - 初始化共享的catalog&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RelationCacheInitializePhase3&lt;/code&gt; - 完成初始化relcache&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RelationIdGetRelation&lt;/code&gt; - 通过relation id获得rel描述&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RelationClose&lt;/code&gt; - 关闭一个relation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这5个阶段是relcache中的5个主要逻辑，相当于一个rel entry的生命周期，而不是relcache的生命周期。前三个阶段都是relcache的初始化，他们会初始化relcache，加载一些系统表和其索引；后两个阶段是获得reldesc的逻辑和关闭relation的逻辑，relcache本身还是存在的。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第一阶段&lt;/em&gt;：&lt;code&gt;RelationCacheInitialize&lt;/code&gt;
&lt;code&gt;RelationCacheInitialize&lt;/code&gt; 初始化relcache：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//定义初始大小400
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define INITRELCACHESIZE		400
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RelationCacheInitialize&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HASHCTL		ctl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			allocsize;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * make sure cache memory context exists
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//检查是否有cache mctx，没有则创建一个
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;CacheMemoryContext)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;CreateCacheMemoryContext&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//创建索引到relcache的哈希表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ctl.keysize &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(Oid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ctl.entrysize &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(RelIdCacheEnt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RelationIdCache &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hash_create&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Relcache by OID&amp;#34;&lt;/span&gt;, INITRELCACHESIZE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ctl, HASH_ELEM &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH_BLOBS);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 初始化relation mapper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;RelationMapInitialize&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RelationCacheInitialize&lt;/code&gt;没有分配任何rel的操作，只是对relcache做初始化内存、hash表、mapper等&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第二阶段&lt;/em&gt;：&lt;code&gt;RelationCacheInitializePhase2&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RelationCacheInitializePhase2&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext oldcxt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//初始化 relation mapper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;RelationMapInitializePhase2&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果是bootstrap模式，共享catalog还不存在，所以可以什么也不做
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsBootstrapProcessingMode&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//switch到当前的cache mctx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	oldcxt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MemoryContextSwitchTo&lt;/span&gt;(CacheMemoryContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//尝试加载共享的relcache file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;load_relcache_init_file&lt;/span&gt;(true))&lt;span style="color:#75715e"&gt;//如果没有加载初始化文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_database&amp;#34;&lt;/span&gt;, DatabaseRelation_Rowtype_Id, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_database, Desc_pg_database);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_authid&amp;#34;&lt;/span&gt;, AuthIdRelation_Rowtype_Id, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_authid, Desc_pg_authid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_auth_members&amp;#34;&lt;/span&gt;, AuthMemRelation_Rowtype_Id, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_auth_members, Desc_pg_auth_members);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_shseclabel&amp;#34;&lt;/span&gt;, SharedSecLabelRelation_Rowtype_Id, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_shseclabel, Desc_pg_shseclabel);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_subscription&amp;#34;&lt;/span&gt;, SubscriptionRelation_Rowtype_Id, true,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_subscription, Desc_pg_subscription);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define NUM_CRITICAL_SHARED_RELS	5	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* fix if you change list above */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;MemoryContextSwitchTo&lt;/span&gt;(oldcxt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;init file分为了shared 和local cache init file，&lt;code&gt;load_relcache_init_file()&lt;/code&gt;就是尝试从这两种文件中load数据到relcache中（这里应该只加载共享的）。如果load失败，则创建&lt;code&gt;pg_database&lt;/code&gt;、&lt;code&gt;pg_authid&lt;/code&gt;等5个基本的系统表的描述信息。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第三阶段&lt;/em&gt;：
&lt;code&gt;RelationCacheInitializePhase3&lt;/code&gt;初始化的第三阶段，内容也是最多的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RelationCacheInitializePhase3&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HASH_SEQ_STATUS status;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RelIdCacheEnt &lt;span style="color:#f92672"&gt;*&lt;/span&gt;idhentry;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext oldcxt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		needNewCacheFile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;criticalSharedRelcachesBuilt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;RelationMapInitializePhase3&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//切换到CacheMemoryContext
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	oldcxt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MemoryContextSwitchTo&lt;/span&gt;(CacheMemoryContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//跟2阶段差不多，加载更多的系统表描述
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsBootstrapProcessingMode&lt;/span&gt;() &lt;span style="color:#f92672"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;load_relcache_init_file&lt;/span&gt;(false))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		needNewCacheFile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_class&amp;#34;&lt;/span&gt;, RelationRelation_Rowtype_Id, false,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_class, Desc_pg_class);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_attribute&amp;#34;&lt;/span&gt;, AttributeRelation_Rowtype_Id, false,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_attribute, Desc_pg_attribute);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_proc&amp;#34;&lt;/span&gt;, ProcedureRelation_Rowtype_Id, false,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_proc, Desc_pg_proc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;formrdesc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_type&amp;#34;&lt;/span&gt;, TypeRelation_Rowtype_Id, false,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Natts_pg_type, Desc_pg_type);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define NUM_CRITICAL_LOCAL_RELS 4	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* fix if you change list above */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;MemoryContextSwitchTo&lt;/span&gt;(oldcxt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果我们还没有获得关键的系统索引，现在就做 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//因为catcache and/or opclass cache依赖relcache中的关键系统索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;criticalRelcachesBuilt)&lt;span style="color:#75715e"&gt;//如果未load关键索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;load_critical_index&lt;/span&gt;(ClassOidIndexId,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							RelationRelationId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;load_critical_index&lt;/span&gt;(TriggerRelidNameIndexId,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							TriggerRelationId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define NUM_CRITICAL_LOCAL_INDEXES	7	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* fix if you change list above */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		criticalRelcachesBuilt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true; &lt;span style="color:#75715e"&gt;//打个标记，关键系统表索引已获得
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//继续处理共享的关键系统表索引。这些共享关键系统表在某些情况（autovacuum、客户端认证等）下需要
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;criticalSharedRelcachesBuilt)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;load_critical_index&lt;/span&gt;(DatabaseNameIndexId,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							DatabaseRelationId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;load_critical_index&lt;/span&gt;(SharedSecLabelObjectIndexId,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							SharedSecLabelRelationId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define NUM_CRITICAL_SHARED_INDEXES 6	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* fix if you change list above */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		criticalSharedRelcachesBuilt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;&lt;span style="color:#75715e"&gt;//打个标记，共享关键系统表索引已获得
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//扫描relcache中的所有条目并更新那些在formrdesc 或init file中有错误的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//如果有错误，读pg_class数据然后替换错误条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//因为cache file中没有rule、trigger、安全策略，同时也从pg_class中获取
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ((idhentry &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (RelIdCacheEnt &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;hash_seq_search&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;status)) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		Relation	relation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; idhentry&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;reldesc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//确保正在使用的relation不要flush
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;RelationIncrementReferenceCount&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 &lt;span style="color:#75715e"&gt;//如果是错误的条目，从pg_class中读元组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relowner &lt;span style="color:#f92672"&gt;==&lt;/span&gt; InvalidOid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;((&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel, (&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) relp, CLASS_TUPLE_SIZE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//更新rd_option
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_options)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;pfree&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_options);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationParseRelOptions&lt;/span&gt;(relation, htup);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ReleaseSysCache&lt;/span&gt;(htup);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//修复那些不在init file中的数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//例如relhasrules、relhastriggers可能已经过时或错误了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relhasrules &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rules &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationBuildRuleLock&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rules &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relhasrules &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relhastriggers &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;trigdesc &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationBuildTriggers&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;trigdesc &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relhastriggers &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 &lt;span style="color:#75715e"&gt;//reload行安全策略，因为init文件里没有
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relrowsecurity &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rsdesc &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationBuildRowSecurity&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rsdesc &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果需要reload tableam
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_tableam &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			(&lt;span style="color:#a6e22e"&gt;RELKIND_HAS_TABLE_AM&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relkind) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relkind &lt;span style="color:#f92672"&gt;==&lt;/span&gt; RELKIND_SEQUENCE))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationInitTableAccessMethod&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_tableam &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			restart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//持有数计数-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;RelationDecrementReferenceCount&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//最后，如果需要，更新init file（毕竟可能有reload，别浪费了）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (needNewCacheFile)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;InitCatalogCachePhase2&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* now write the files */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;write_relcache_init_file&lt;/span&gt;(true); &lt;span style="color:#75715e"&gt;//写global init file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;write_relcache_init_file&lt;/span&gt;(false); &lt;span style="color:#75715e"&gt;//写private init file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RelationCacheInitializePhase3()&lt;/code&gt;相比于2阶段加载的5个系统表，加载了更多的系统表，比如&lt;code&gt;pg_class&lt;/code&gt;、&lt;code&gt;pg_proc&lt;/code&gt;等，以及加载这些表上的索引。当然这些rel加载的前提是cache中没有或者已过期。reload完成后，再把“新”的catalog写入到init file中。
最后写入init file时，看下对应的&lt;code&gt;write_relcache_init_file&lt;/code&gt;函数源码，便可以知道传入参数&lt;code&gt;true&lt;/code&gt;和&lt;code&gt;false&lt;/code&gt;的含义：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;write_relcache_init_file&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; shared)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;···&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (shared)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;snprintf&lt;/span&gt;(tempfilename, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(tempfilename), &lt;span style="color:#e6db74"&gt;&amp;#34;global/%s.%d&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 RELCACHE_INIT_FILENAME, MyProcPid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;snprintf&lt;/span&gt;(finalfilename, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(finalfilename), &lt;span style="color:#e6db74"&gt;&amp;#34;global/%s&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 RELCACHE_INIT_FILENAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;snprintf&lt;/span&gt;(tempfilename, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(tempfilename), &lt;span style="color:#e6db74"&gt;&amp;#34;%s/%s.%d&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;snprintf&lt;/span&gt;(finalfilename, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(finalfilename), &lt;span style="color:#e6db74"&gt;&amp;#34;%s/%s&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 DatabasePath, RELCACHE_INIT_FILENAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;true表示写入到global init file
false表示写入到local init file&lt;/p&gt;
&lt;p&gt;其中&lt;code&gt;RELCACHE_INIT_FILENAME&lt;/code&gt;参数宏定义：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define RELCACHE_INIT_FILENAME &amp;#34;pg_internal.init&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;so，写入的init file为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;shared：&lt;code&gt;global/pg_internal.init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;local：&lt;code&gt;DatabasePath/pg_internal.init&lt;/code&gt; 和 &lt;code&gt;DatabasePath/pg_internal.init.myPID&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们看下真实的init文件路径：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ find ./ -name *init*
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./global/pg_internal.init &lt;span style="color:#75715e"&gt;#shared&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/1/pg_internal.init &lt;span style="color:#75715e"&gt;#local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/13577/pg_internal.init &lt;span style="color:#75715e"&gt;#local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/13578/pg_internal.init	&lt;span style="color:#75715e"&gt;#local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/16398/pg_internal.init	&lt;span style="color:#75715e"&gt;#local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/16811/pg_internal.init	&lt;span style="color:#75715e"&gt;#local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./base/17674/pg_internal.init	&lt;span style="color:#75715e"&gt;#local&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;初始化三阶段的调用示意图：



&lt;img src="https://lastdba.com/img/csdn/f743c6c69083.png" alt="在这里插入图片描述" /&gt;
（https://blog.japinli.top/2022/07/postgres-relcache-and-syscache/）&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第四阶段&lt;/em&gt;：&lt;code&gt;RelationIdGetRelation&lt;/code&gt;
通过OID找到reldesc。caller只需要拿到OID 的AccessShareLock，也要自己加减rel的持有数。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Relation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RelationIdGetRelation&lt;/span&gt;(Oid relationId)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Relation	rd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//确保在事务里
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;IsTransactionState&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//首次尝试在reldesc中找到cache
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;RelationIdCacheLookup&lt;/span&gt;(relationId, rd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;RelationIsValid&lt;/span&gt;(rd))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//已删除的relation返回null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (rd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_droppedSubid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; InvalidSubTransactionId)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;rd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_isvalid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;RelationIncrementReferenceCount&lt;/span&gt;(rd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;rd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_isvalid)&lt;span style="color:#75715e"&gt;//如果cache中的rel是无效的，重新让他有效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (rd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relkind &lt;span style="color:#f92672"&gt;==&lt;/span&gt; RELKIND_INDEX &lt;span style="color:#f92672"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				rd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relkind &lt;span style="color:#f92672"&gt;==&lt;/span&gt; RELKIND_PARTITIONED_INDEX) &lt;span style="color:#75715e"&gt;//索引信息直接加载
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;RelationReloadIndexInfo&lt;/span&gt;(rd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#75715e"&gt;//如果是非索引，则清理reldesc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;RelationClearRelation&lt;/span&gt;(rd, true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; rd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//没有reldesc了，新建一个reldesc 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	rd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RelationBuildDesc&lt;/span&gt;(relationId, true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;RelationIsValid&lt;/span&gt;(rd))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;RelationIncrementReferenceCount&lt;/span&gt;(rd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; rd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RelationIdGetRelation&lt;/code&gt; 比较简单，就是通过OID拿到reldesc和索引信息&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第五阶段&lt;/em&gt;：&lt;code&gt;RelationClose&lt;/code&gt;
&lt;code&gt;RelationClose&lt;/code&gt;的代码也比较简单：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RelationClose&lt;/span&gt;(Relation relation)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//不需要锁的操作，直接简单的refcount-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;RelationDecrementReferenceCount&lt;/span&gt;(relation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//如果没有会话打开relation，可以删除分区描述信息（partition descriptors）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;RelationHasReferenceCountZero&lt;/span&gt;(relation))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pdcxt &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pdcxt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;firstchild &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;MemoryContextDeleteChildren&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pdcxt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pddcxt &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pddcxt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;firstchild &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;MemoryContextDeleteChildren&lt;/span&gt;(relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_pddcxt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifdef RELCACHE_FORCE_RELEASE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;RelationHasReferenceCountZero&lt;/span&gt;(relation) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_createSubid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; InvalidSubTransactionId &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		relation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_firstRelfilenodeSubid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; InvalidSubTransactionId)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;RelationClearRelation&lt;/span&gt;(relation, false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RelationClose &lt;/code&gt;是对关闭访问relation的操作，一般来说这个函数只会将访问relation的会话数&lt;code&gt;refcount&lt;/code&gt;减少。但是也有例外情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当&lt;code&gt;refcount&lt;/code&gt;为0时，会执行&lt;code&gt;MemoryContextDeleteChildren()&lt;/code&gt;，这个&lt;code&gt;MemoryContextDeleteChildren()&lt;/code&gt;函数，将删除其&lt;em&gt;子分区描述&lt;/em&gt;相关的mctx，这个是会释放内存的。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;refcount&lt;/code&gt;为0且有标记宏定义&lt;code&gt;DRELCACHE_FORCE_RELEASE&lt;/code&gt;时，使用&lt;code&gt;RelationClearRelation()&lt;/code&gt;函数删除hash表的entry，这一步不会释放内存。这个&lt;code&gt;DRELCACHE_FORCE_RELEASE&lt;/code&gt;宏没有找到（只有显示编译才会有？）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;relcache也不是完全没有释放内存的逻辑，不过触发条件比较苛刻，且删除的内存也不是relcache中的所有内存。&lt;/em&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;syscache/catcache
 &lt;div id="syscachecatcache" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#syscachecatcache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;CatCache缓存的是系统表中的Tuple，基于CatCache基础之上还有一层SysCache（KV接口），本质上可以认为CatCache和SysCache一起把系统表中的数据在内存中按照KV方式重新组织。
syscache/catcache要更复杂一点，这里简单提炼一点容易解读的内容，主要是为了了解syscache的缓存内容和load机制。进一步的源码解读可参阅&lt;a href="https://blog.csdn.net/weixin_45644897/article/details/121254012" target="_blank" rel="noreferrer"&gt;postgreSQL源码分析——存储管理——内存管理（3）&lt;/a&gt;和&lt;a href="https://blog.japinli.top/2022/07/postgres-relcache-and-syscache/" target="_blank" rel="noreferrer"&gt; PostgreSQL RelCache 和 SysCache 缓存&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;catcache结构体&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; catcache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			id;				&lt;span style="color:#75715e"&gt;//cache id,id定义在syscache.h中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			cc_nbuckets;	&lt;span style="color:#75715e"&gt;//这个cache的hash桶个数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TupleDesc	cc_tupdesc;		&lt;span style="color:#75715e"&gt;//元组描述，由reldesc拷贝而来
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cc_relname;		&lt;span style="color:#75715e"&gt;//元组对应的系统表名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			cc_reloid;		&lt;span style="color:#75715e"&gt;//系统表的OID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			cc_indexoid;	&lt;span style="color:#75715e"&gt;//cache key的索引OID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		cc_relisshared; &lt;span style="color:#75715e"&gt;//表是否跨db共享？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//catcache使用的统计信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifdef CATCACHE_STATS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;		cc_searches;	&lt;span style="color:#75715e"&gt;//查询该catcache的次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;		cc_hits;		&lt;span style="color:#75715e"&gt;//命中次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;		cc_neg_hits;	&lt;span style="color:#75715e"&gt;//negative entry的命中次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} CatCache;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;catcache条目&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; catctup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			ct_magic;		&lt;span style="color:#75715e"&gt;//标识catctup条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CT_MAGIC 0x57261502
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint32		hash_value;		&lt;span style="color:#75715e"&gt;//这个tuple的hash键值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//不会返回死元组，但是在refcount变成零时，会从catcache中删除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			refcount;		&lt;span style="color:#75715e"&gt;//元组的refcount，标志是否有访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		dead;			&lt;span style="color:#75715e"&gt;//死元组，但是还没有清理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		negative;		&lt;span style="color:#75715e"&gt;//是否是negative cache entry? 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HeapTupleData tuple;		&lt;span style="color:#75715e"&gt;//元组头结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CatCache &lt;span style="color:#f92672"&gt;*&lt;/span&gt;my_cache;		&lt;span style="color:#75715e"&gt;//链接到该元组所属的catcache
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} CatCTup;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;SearchCatCacheMiss()函数&lt;/strong&gt;
SearchCatCacheMiss()是catcache hit miss的主要函数,并且在miss后会产生访问字典中的元组&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; pg_noinline HeapTuple
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SearchCatCacheMiss&lt;/span&gt;(CatCache &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cache,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; nkeys,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 uint32 hashValue,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Index hashIndex,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Datum v1,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Datum v2,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Datum v3,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 Datum v4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ScanKeyData cur_skey[CATCACHE_MAXKEYS];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Relation	relation;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SysScanDesc scandesc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HeapTuple	ntp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CatCTup &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ct;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Datum		arguments[CATCACHE_MAXKEYS];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//cache中未找到元组,所以需要尝试直接从表中找
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//找到就加到cache中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//没有找到就加一个negative cache条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	relation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;table_open&lt;/span&gt;(cache&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_reloid, AccessShareLock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	scandesc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;systable_beginscan&lt;/span&gt;(relation,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 cache&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_indexoid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#a6e22e"&gt;IndexScanOK&lt;/span&gt;(cache, cur_skey),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 nkeys,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 cur_skey);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ct &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//元组有效时,创建一个条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleIsValid&lt;/span&gt;(ntp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;systable_getnext&lt;/span&gt;(scandesc)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		ct &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CatalogCacheCreateEntry&lt;/span&gt;(cache, ntp, arguments,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									 hashValue, hashIndex,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									 false); &lt;span style="color:#75715e"&gt;//创建一个条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//refcount立即+1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ResourceOwnerEnlargeCatCacheRefs&lt;/span&gt;(CurrentResourceOwner);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		ct&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;refcount&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ResourceOwnerRememberCatCacheRef&lt;/span&gt;(CurrentResourceOwner, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ct&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;					&lt;span style="color:#75715e"&gt;/* assume only one match */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;systable_endscan&lt;/span&gt;(scandesc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;table_close&lt;/span&gt;(relation, AccessShareLock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	//如果没有找到元组,需要创建一个negative cache条目,相当于假元组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	//假元组有key column,其余都是null的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	//,因为在启动阶段invalidation机制未激活且在元组真的在稍后创建后无法清理他们
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	//所以这个阶段,不会创建negative条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	if (ct == NULL) //如果没有找到元组,进入以下逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		if (IsBootstrapProcessingMode()) //如果是启动阶段直接返回NULL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			return NULL;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		ct = CatalogCacheCreateEntry(cache, NULL, arguments,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;									 hashValue, hashIndex,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;									 true); //创建条目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		CACHE_elog(DEBUG2, &amp;#34;SearchCatCache(%s): Contains %d/%d tuples&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 cache-&amp;gt;cc_relname, cache-&amp;gt;cc_ntup, CacheHdr-&amp;gt;ch_ntup);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		CACHE_elog(DEBUG2, &amp;#34;SearchCatCache(%s): put neg entry in bucket %d&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 cache-&amp;gt;cc_relname, hashIndex);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		//negative条目不返回给caller,refcount也是0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		return NULL;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	return &amp;amp;ct-&amp;gt;tuple;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里的假元组&lt;em&gt;negative cache entry&lt;/em&gt;很精彩，将一个不存在的元组缓存在catcache中，下次再发生访问就不需要再到数据字典中找元组了，避免了无意义的多次查数据字典。&lt;/p&gt;

&lt;h3 class="relative group"&gt;cache validation消息
 &lt;div id="cache-validation消息" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cache-validation%e6%b6%88%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;当元组发生update或delete后，由于事务可见性规则，这些在事务结束后不可见的元组需要被告知给cache，使cache中的元组invalidated，在下次读取时再load。同样，因为insert而产生新元组时,cache中的negative cache entry也可能需要flush出去以匹配新元组。其中一个比较常见的常见是DDL，DDL可能导致元数据中的某些tuple失效，此时就需要发送cache validation给各个私有cache让他们清理cache条目。
这个cache validation机制适用于syscache、relcache等私有cache池的管理。由于idle的backend不会读sinval events,所以需要主动send消息让lag backend能“catch up”。当完成事务时，必须要将invalidation events通过SI message queue广播给其他backends。&lt;/p&gt;
&lt;p&gt;源码分为两块，&lt;code&gt;sinval&lt;/code&gt;和&lt;code&gt;inval&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Invalidation interface: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/include/utils/inval.h;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/include/utils/inval.h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invalidation dispatch: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/backend/utils/cache/inval.c;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/backend/utils/cache/inval.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invalidation message sharing interface: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/include/storage/sinval.h;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/include/storage/sinval.h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invalidation message sharing dispatch: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/backend/storage/ipc/sinval.c;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/backend/storage/ipc/sinval.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invalidation message sharing data structures interface: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/include/storage/sinvaladt.h;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/include/storage/sinvaladt.h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invalidation message sharing data structures: &lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;f=src/backend/storage/ipc/sinvaladt.c;hb=HEAD" target="_blank" rel="noreferrer"&gt;src/backend/storage/ipc/sinvaladt.c&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;src/backend/utils/cache/inval.c&lt;/code&gt;中包含shared-invalidation消息结构体：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	int8		id;				&lt;span style="color:#75715e"&gt;/* type field --- must be first */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalCatcacheMsg cc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalCatalogMsg cat;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalRelcacheMsg rc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalSmgrMsg sm;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalRelmapMsg rm;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SharedInvalSnapshotMsg sn;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} SharedInvalidationMessage;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;shared-invalidation消息包含如下种类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使指定catcache条目失效&lt;/li&gt;
&lt;li&gt;使某个系统catalog的整个catcache条目失效&lt;/li&gt;
&lt;li&gt;使指定relcache条目失效&lt;/li&gt;
&lt;li&gt;使所有relcache条目失效&lt;/li&gt;
&lt;li&gt;使某个对应物理relation的smgr的cache条目失效&lt;/li&gt;
&lt;li&gt;使 mapped-relation 失效&lt;/li&gt;
&lt;li&gt;使扫描过relation的保存了的快照失效&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;消息位于共享内存队列中，直到所有其他进程读取它们。通常，接收进程仅在特定时间读取消息，因此，如果接收进程处于空闲状态（即不处理任何用户请求）或忙于执行其他操作，以至于它们没有时间读取这些消息，则消息可能会无限期地继续留在共享内存中。在不幸的情况下，如果此共享内存空间不再可用于进程来存储新消息，则该进程将不得不承担清理任务。（实际上，这种清理是主动完成的，因此很少会用完空间）若要丢弃旧消息，必须确保所有其他进程都已读取它们。如果某些进程由于上述原因无法做到这一点，它必须明确地向滞后的进程发送信号，要求它们赶上。一旦滞后进程赶上来，就可以随意丢弃这些消息。
处理消息时，首先检查消息中指定的目录元组当前是否在缓存中（消息中还指定了 syscache 标识），如果是，则将其从缓存的哈希表中删除。下次请求该元组时，将从基础目录表中重新读取该元组并将其添加到哈希表中，因此后续访问将读取新值。如果进程已锁定特定数据库对象，阻止并发进程再修改它，则它可以继续使用缓存的元组，直到释放锁定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 class="relative group"&gt;xxCache的问题小结
 &lt;div id="xxcache的问题小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#xxcache%e7%9a%84%e9%97%ae%e9%a2%98%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;xxCache有许多种类，其中比较著名的有plancache、relcache、syscache。这些cache属于私有内存，存在于每个backend进程中。这些cache没有lru机制来淘汰过期的数据，他们通过invalidation消息清理全局都不需要的快照、元数据信息，比如对象被删除了的时候。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;relcache是最有可能占用较多内存的地方，relcache会加载元数据信息，初始化过程中会读取*.init文件以加快加载元数据到relcache中。后续在需要读取到其他元数据时，也会进行加载。&lt;/li&gt;
&lt;li&gt;catcache缓存数据字典的元组信息，syscache是基于catcache上一层的，可理解为他俩一起实现这个数据字段缓存。如果元组不存在，则会生成一个negative条目，以访下次访问还要访问数据字典。同样的，catcache miss也会去读数据字典中的元组。&lt;/li&gt;
&lt;li&gt;cache validation消息是为了告知cache中缓存的元组、快照信息已经过久，它可以使对应的relcache、catcache条目失效。条目会从从缓存的哈希表中删除，这一步会释放内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于cache的内存释放机制很少，当元数据较多的时候（很多的表、分区表），relcache、catcache可能会占用很多内存，而且是每个backend多有可能这样。
&lt;em&gt;可能的解决办法&lt;/em&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;global cache。像oracle的dictionary cache那样，缓存在一个地方，共享访问。如&lt;a href="https://www.alibabacloud.com/help/en/polardb/polardb-for-postgresql/global-relcache-1" target="_blank" rel="noreferrer"&gt;PolarDB的Global RelCache&lt;/a&gt;已实现此功能&lt;/li&gt;
&lt;li&gt;LRU。需要适合cache的LRU机制将冷热端分离，过旧的cache条目从hash table中清理即可。此时可能需要cache limit参数限制cache的大小，最好每个cache来一个···&lt;/li&gt;
&lt;li&gt;线程模式。内存对于线程来说都共享的访问的，天然的优势&lt;/li&gt;
&lt;li&gt;定期断开长连接。以上都是空了吹。&lt;/li&gt;
&lt;li&gt;不要建太多的表、分区（注意pg中分区表的分区也是表）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;memory contexts
 &lt;div id="memory-contexts" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#memory-contexts" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PostgresSQL通过memory context机制来管理内存。之前有做过&lt;a href="https://blog.csdn.net/qq_40687433/article/details/134796339?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;一篇memory contexts的译文&lt;/a&gt;，大致总结如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C语言必须显示释放内存，为了减少内存泄漏的风险，PostgreSQL实现了memory contexts来管理私有内存&lt;/li&gt;
&lt;li&gt;memory contexts不需要每次用完都释放内存，而是通过删除某个context来实现内存释放&lt;/li&gt;
&lt;li&gt;memory contexts是一个层级结构，父级context的释放会递归删除所有子contexts&lt;/li&gt;
&lt;li&gt;除了调试之外，memory contexts的内存使用情况是比较难观察的。pg14开始有pg_backend_memory_contexts视图可以观察当前会话的当前memory_context使用情况&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQL操作产生memory context的时机：



&lt;img src="https://lastdba.com/img/csdn/b269e3547cbf.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.pgcon.org/2019/schedule/attachments/514_introduction-memory-contexts.pdf)&lt;/p&gt;

&lt;h3 class="relative group"&gt;源码分析
 &lt;div id="源码分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在 PostgreSQL 中，所有内存的申请、释放和重置都是在内存上下文中进行的，因此不会直接使用 &lt;code&gt;malloc()&lt;/code&gt;、&lt;code&gt;realloc()&lt;/code&gt; 和 &lt;code&gt;free()&lt;/code&gt; 系统调用函数，而是使用 &lt;code&gt;palloc()&lt;/code&gt;、&lt;code&gt;repalloc()&lt;/code&gt; 和 &lt;code&gt;pfree()&lt;/code&gt; 来实现内存的分配、重分配和释放。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C库的内存函数&lt;/strong&gt;
&lt;a href="https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/" target="_blank" rel="noreferrer"&gt;C库动态内存分配函数&lt;/a&gt;有如下几个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;malloc()：C库的malloc()函数（memory allocation）用于分配大块内存&lt;/li&gt;
&lt;li&gt;calloc()：C库的calloc()函数（contiguous allocation）用于分配连续内存&lt;/li&gt;
&lt;li&gt;free()：用于释放内存。malloc()，calloc()不会释放内存，动态分配内存后都需要用free()释放内存&lt;/li&gt;
&lt;li&gt;realloc()：用于重新分配内存（re-allocation）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外还有一个C库函数&lt;a href="https://www.geeksforgeeks.org/memset-c-example/" target="_blank" rel="noreferrer"&gt;memset()&lt;/a&gt;，用来给内存块填充具体的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg代码定义的内存函数&lt;/strong&gt;
真正被PostgreSQL源码大量调用的内存申请、释放等函数是&lt;code&gt;palloc()&lt;/code&gt;、&lt;code&gt;palloc0()&lt;/code&gt;，&lt;code&gt;repalloc()&lt;/code&gt;，&lt;code&gt;pfree()&lt;/code&gt;。他们大部分情况下不会直接跟操作系统内存（C库函数）交互，只有某些情况下会调用C库内存函数。相当于对操作系统内存操作做了一层保护，对于小内存的操作由pg自己完成。
&lt;strong&gt;palloc()&lt;/strong&gt;:
&lt;code&gt;palloc()&lt;/code&gt;主要是调用&lt;code&gt;MemoryContext&lt;/code&gt;的方法&lt;code&gt;alloc&lt;/code&gt;。&lt;code&gt;alloc&lt;/code&gt;是对&lt;code&gt;MemoryContextAlloc&lt;/code&gt;函数的调用，而&lt;code&gt;MemoryContextAlloc&lt;/code&gt;函数实际上是调用了当前内存上下文的methods字段中所指定的&lt;code&gt;AllocSetAlloc&lt;/code&gt;函数&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;palloc&lt;/span&gt;(Size size)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* duplicates MemoryContextAlloc to avoid increased overhead */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CurrentMemoryContext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;methods&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alloc&lt;/span&gt;(context, size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;....
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;palloc0()&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;palloc0&lt;/span&gt;(Size size)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;methods&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alloc&lt;/span&gt;(context, size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;MemSetAligned&lt;/span&gt;(ret, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;MemSetAligned&lt;/code&gt;是宏定义的，实际上就是调用C库的&lt;code&gt;memset&lt;/code&gt;做内存填充，不过&lt;code&gt;MemSetAligned&lt;/code&gt;传入的value是&lt;code&gt;0&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MemSetAligned(start, val, len)\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;...\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	memset(_start, _val, _len); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;...	&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;palloc0&lt;/code&gt;相对&lt;code&gt;pallo&lt;/code&gt;，除了都调用&lt;code&gt;alloc(context, size)&lt;/code&gt;，&lt;code&gt;palloc0&lt;/code&gt;还会把内存的内容置&lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;repalloc()&lt;/strong&gt;:
&lt;code&gt;realloc()&lt;/code&gt;主要是调用&lt;code&gt;MemoryContext&lt;/code&gt;的方法&lt;code&gt;realloc&lt;/code&gt;，&lt;code&gt;realloc&lt;/code&gt;函数指针对应于&lt;code&gt;AllocSetRealloc&lt;/code&gt;函数&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * repalloc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		Adjust the size of a previously allocated chunk.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;repalloc&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pointer, Size size)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetMemoryChunkContext&lt;/span&gt;(pointer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;methods&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;realloc&lt;/span&gt;(context, pointer, size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;pfree()&lt;/strong&gt;:
pfree将调用内存片所属的内存上下文的methods字段中的free_p函数指针来释放内存片的空间。目前，PG中free_p指针实际指向AllocSetFree函数&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * pfree
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		Release an allocated chunk.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pfree&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pointer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MemoryContext context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetMemoryChunkContext&lt;/span&gt;(pointer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	context&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;methods&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;free_p&lt;/span&gt;(context, pointer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;VALGRIND_MEMPOOL_FREE&lt;/span&gt;(context, pointer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;AllocSetAlloc分配内存&lt;/strong&gt;
查看其中的alloc方法，alloc最终指向AllocSetAlloc函数。AllocSetAlloc看上去比较复杂，分段看的话比较好理解：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;AllocSetAlloc&lt;/span&gt;(MemoryContext context, Size size)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	AllocSet	set &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (AllocSet) context;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	AllocBlock	block;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	AllocChunk	chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			fidx;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Size		chunk_size;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Size		blksize;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果申请的内存大小超过chunk的最大值，分配整个内存block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (size &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; set&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;allocChunkLimit)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		block &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (AllocBlock) &lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(blksize);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果申请的内存大小小于chunk，从free list中找是否有free chunk可以使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	fidx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AllocSetFreeIndex&lt;/span&gt;(size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	chunk &lt;span style="color:#f92672"&gt;=&lt;/span&gt; set&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;freelist[fidx];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (chunk &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL) &lt;span style="color:#75715e"&gt;//freelist中有chunk可以使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(chunk&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;size &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; size);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		set&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;freelist[fidx] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (AllocChunk) chunk&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;aset;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		chunk&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;aset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) set;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AllocChunkGetPointer&lt;/span&gt;(chunk);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;//如果有空间，尝试把chunk放到allocation block，如果没有，需要新建一个block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((block &lt;span style="color:#f92672"&gt;=&lt;/span&gt; set&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;blocks) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		Size		availspace &lt;span style="color:#f92672"&gt;=&lt;/span&gt; block&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;endptr &lt;span style="color:#f92672"&gt;-&lt;/span&gt; block&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;freeptr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (availspace &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; (chunk_size &lt;span style="color:#f92672"&gt;+&lt;/span&gt; ALLOC_CHUNKHDRSZ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			block &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//没有空间，创建新block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (block &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		Size		required_size;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//申请的block大小为2的冥，不超过 maxBlockSize
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		required_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; chunk_size &lt;span style="color:#f92672"&gt;+&lt;/span&gt; ALLOC_BLOCKHDRSZ &lt;span style="color:#f92672"&gt;+&lt;/span&gt; ALLOC_CHUNKHDRSZ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (blksize &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; required_size)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			blksize &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//使用malloc分配块，size为2的冥
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		block &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (AllocBlock) &lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(blksize);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8731cbdd1398.png" alt="Alt text" /&gt;&lt;/p&gt;
&lt;p&gt;（https://smartkeyerror.com/PostgreSQL-MemoryContext）&lt;/p&gt;
&lt;p&gt;palloc()=&amp;gt;AllocSetAlloc()只有在申请的内存超过chunk大小限制或者freelist中没有空闲block的时候，才会调用malloc()去向操作系统申请内存；其余情况都是在freelist中拿已有的free chunk。&lt;/p&gt;
&lt;p&gt;pfree()也是类似的（不示例了）：
pfree()=&amp;gt;AllocSetFree()释放一个内存上下文中指定的内存片，如果指定要释放的内存片是内存块中唯一的一个内存片，则将调用free()直接释放该内存块。否则，将指定的内存片加入到Freelist链表中以便下次分配&lt;/p&gt;

&lt;h3 class="relative group"&gt;查看mcxt内存大小
 &lt;div id="查看mcxt内存大小" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9f%a5%e7%9c%8bmcxt%e5%86%85%e5%ad%98%e5%a4%a7%e5%b0%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;pg14+：pg_backend_memory_contexts 视图直接在库内查看mcxt内存&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_backend_memory_contexts &lt;span style="color:#66d9ef"&gt;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; used_bytes &lt;span style="color:#66d9ef"&gt;DESC&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LIMIT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ident &lt;span style="color:#f92672"&gt;|&lt;/span&gt; parent &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;level&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; total_bytes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; total_nblocks &lt;span style="color:#f92672"&gt;|&lt;/span&gt; free_bytes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; free_chunks &lt;span style="color:#f92672"&gt;|&lt;/span&gt; used_bytes 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------------+-------+------------------+-------+-------------+---------------+------------+-------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CacheMemoryContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TopMemoryContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1048576&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;508216&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;540360&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Timezones &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TopMemoryContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;104120&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2616&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;101504&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TopMemoryContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;97680&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12904&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;84776&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ExecutorState &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; PortalContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;49208&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4424&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;44784&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WAL record construction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TopMemoryContext &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;49768&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6360&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;43408&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;pg14+：pg_log_backend_memory_contexts函数输出内存信息到log文件，输出类似MemoryContextStats(TopMemoryContext)的log输出&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; pg_log_backend_memory_contexts(&lt;span style="color:#ae81ff"&gt;9293&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;通用-gdb MemoryContextStats(TopMemoryContext)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;gdb调用MemoryContextStats(TopMemoryContext)：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gdb 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;gdb&lt;span style="color:#f92672"&gt;)&lt;/span&gt; attach &lt;span style="color:#ae81ff"&gt;9293&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;gdb&lt;span style="color:#f92672"&gt;)&lt;/span&gt; p MemoryContextStats&lt;span style="color:#f92672"&gt;(&lt;/span&gt;TopMemoryContext&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; void&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;log输出：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TopMemoryContext: &lt;span style="color:#ae81ff"&gt;97680&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;16856&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;80824&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TableSpace cache: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;2088&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;6104&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RowDescriptionContext: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;6888&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1304&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MessageContext: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;6888&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1304&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Operator class cache: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;552&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;7640&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Relcache by OID: &lt;span style="color:#ae81ff"&gt;16384&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;3504&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;12880&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CacheMemoryContext: &lt;span style="color:#ae81ff"&gt;524288&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;90840&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;433448&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index info: &lt;span style="color:#ae81ff"&gt;2048&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;904&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1144&lt;/span&gt; used: pg_statistic_ext_relid_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index info: &lt;span style="color:#ae81ff"&gt;2048&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;824&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1224&lt;/span&gt; used: pg_database_oid_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index info: &lt;span style="color:#ae81ff"&gt;2048&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;824&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1224&lt;/span&gt; used: pg_authid_rolname_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WAL record construction: &lt;span style="color:#ae81ff"&gt;49768&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;6360&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;43408&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PrivateRefCount: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;2616&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;5576&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MdSmgr: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;7592&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LOCALLOCK hash: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;552&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;7640&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Timezones: &lt;span style="color:#ae81ff"&gt;104120&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;2616&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;101504&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ErrorContext: &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;7928&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;264&lt;/span&gt; used&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;小结
 &lt;div id="小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/cac547b38cb3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;references
 &lt;div id="references" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;src/backend/utils/mmgr/mcxt.c&lt;/p&gt;
&lt;p&gt;src/backend/utils/mmgr/README&lt;/p&gt;
&lt;p&gt;&lt;a href="https://momjian.us/main/writings/pgsql/inside_shmem.pdf" target="_blank" rel="noreferrer"&gt;https://momjian.us/main/writings/pgsql/inside_shmem.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/pgsql02.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql02.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/runtime-config-resource.htm" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/runtime-config-resource.htm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/kernel-resources.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/kernel-resources.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/weixin_45644897/article/details/121340327" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/weixin_45644897/article/details/121340327&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://help.aliyun.com/zh/polardb/polardb-for-postgresql/global-cache" target="_blank" rel="noreferrer"&gt;https://help.aliyun.com/zh/polardb/polardb-for-postgresql/global-cache&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_cache02.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_cache02.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.japinli.top/2022/07/postgres-relcache-and-syscache/" target="_blank" rel="noreferrer"&gt;https://blog.japinli.top/2022/07/postgres-relcache-and-syscache/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://amitlan.com/2019/06/14/caches-inval.html" target="_blank" rel="noreferrer"&gt;https://amitlan.com/2019/06/14/caches-inval.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cybertec-postgresql.com/en/memory-context-for-postgresql-memory-management/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/memory-context-for-postgresql-memory-management/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/" target="_blank" rel="noreferrer"&gt;https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_mmgr01.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_mmgr01.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_mmgr02.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/feishujun/p/PostgreSQLSourceAnalysis_mmgr02.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://smartkeyerror.com/PostgreSQL-MemoryContext" target="_blank" rel="noreferrer"&gt;https://smartkeyerror.com/PostgreSQL-MemoryContext&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jnidzwetzki.github.io/2022/05/28/postgres-memory-context.html" target="_blank" rel="noreferrer"&gt;https://jnidzwetzki.github.io/2022/05/28/postgres-memory-context.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pgcon.org/2019/schedule/attachments/514_introduction-memory-contexts.pdf" target="_blank" rel="noreferrer"&gt;https://www.pgcon.org/2019/schedule/attachments/514_introduction-memory-contexts.pdf&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL事务浅析</title><link>https://lastdba.com/2024/08/12/postgresql%E4%BA%8B%E5%8A%A1%E6%B5%85%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql%E4%BA%8B%E5%8A%A1%E6%B5%85%E6%9E%90/</guid><description>&lt;p&gt;&lt;strong&gt;PG的事务&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了保证事务的ACID特性，rdbms必须要实现并发控制。pg和oracle、mysql(innodb)数据库都使用MVCC来实现并发控制。MVCC通过数据变化时不断生成新版本对象和可查询一定范围的老版本对象来实现并发，MVCC保存数据在某个时间点的快照，读数时选择一个版本进行读取。&lt;/p&gt;</description><content:encoded>&lt;p&gt;&lt;strong&gt;PG的事务&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了保证事务的ACID特性，rdbms必须要实现并发控制。pg和oracle、mysql(innodb)数据库都使用MVCC来实现并发控制。MVCC通过数据变化时不断生成新版本对象和可查询一定范围的老版本对象来实现并发，MVCC保存数据在某个时间点的快照，读数时选择一个版本进行读取。&lt;/p&gt;
&lt;p&gt;oracle、mysql都通过undo来记录老版本对象，pg没有undo，而是在DML时在直接将历史数据写在原表上（update会创建新行，delete标记行），并在表中记录额外的列xmin,xmax来记录事务号，通过对比事务号和一些其他信息来实现mvcc机制。&lt;/p&gt;
&lt;p&gt;在众多关系型数据库中，pg的事务机制非常有特色，了解pg的事务机制是了解pg数据库运行原理的关键。&lt;/p&gt;

&lt;h2 class="relative group"&gt;事务隔离级别
 &lt;div id="事务隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;一般关系型数据库都可以设置多个不同的事务隔离级别。在不步的事务隔离级别下，事务并发行为有所不同&lt;/p&gt;

&lt;h3 class="relative group"&gt;设置事务隔离级别
 &lt;div id="设置事务隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%ae%be%e7%bd%ae%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg支持设置4种事务隔离级别（实际上只会生效有3个）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SERIALIZABLE&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPEATABLE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;READ&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;READ&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COMMITTED&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;READ&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;UNCOMMITTED&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;事务隔离级别参数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;default_transaction_isolation&lt;/code&gt;：设置全局事务的默认隔离级别&lt;/p&gt;
&lt;p&gt;&lt;code&gt;transaction_isolation&lt;/code&gt;:设置当前会话的事务隔离级别&lt;/p&gt;
&lt;p&gt;默认隔离级别&lt;code&gt;read committed&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;修改全局事务的默认隔离级别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;直接修改&lt;code&gt;default_transaction_isolation&lt;/code&gt;参数，然后&lt;code&gt;reload&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;修改完成后，每个新的事物都会使用&lt;code&gt;default_transaction_isolation&lt;/code&gt;隔离级别&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;postgres=# alter system set default_transaction_isolation to &amp;#39;serializable&amp;#39;;
ALTER SYSTEM
postgres=# select pg_reload_conf();
 pg_reload_conf 
----------------
 t
 (1 row)
 postgres=# show transaction_isolation;
 transaction_isolation 
-----------------------
 serializable&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;设置当前会话的隔离级别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注意参数&lt;code&gt;transaction_isolation&lt;/code&gt;只是展示当前会话的隔离级别，这个参数是不可以直接修改的&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# alter system set transaction_isolation to &amp;#39;REPEATABLE READ&amp;#39;;
ERROR: parameter &amp;#34;transaction_isolation&amp;#34; cannot be changed&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;通过&lt;code&gt;SET SESSION&lt;/code&gt;修改会话的隔离级别，例如：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET
lzldb=# show transaction_isolation ;
-[ RECORD 1 ]---------+----------------
transaction_isolation | repeatable read&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;设置事务的隔离级别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;pg可以指定事务本身的隔离级别&lt;/p&gt;
&lt;p&gt;可通过在开启事务时设置事务的隔离级别，例如：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
lzldb=# start TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;或者开启事务后&lt;code&gt;set transaction&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# begin;
BEGIN
lzldb=*# set transaction ISOLATION LEVEL REPEATABLE READ;
SET&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;ANSI92的事务隔离级别
 &lt;div id="ansi92的事务隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansi92%e7%9a%84%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在&lt;em&gt;ANSI SQL-92&lt;/em&gt;事务隔离级别标准中包含4种隔离级别：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serializable(可串行化或称可序列号)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;系统中所有的事务串行化执行，事务之间互不影响。&lt;/p&gt;
&lt;p&gt;以串行地方式逐个执行，能避免所有数据不一致情况。&lt;/p&gt;
&lt;p&gt;早期以排他锁来控制并发事务，串行化执行方式会导致事务排队，系统的并发量大幅下，不过ANSI 92后出现更多序列化实现方法，并发性和性能均有较大提升。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Repeatable read(可重复读)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个事务一旦开始，事务过程中所读取的所有数据不允许被其他事务修改。可重复读是mysql的默认隔离级别。&lt;/p&gt;
&lt;p&gt;注意， 在ANSI SQL中可重复读级别可发生幻读，但是pg的可重复读不会发生幻读&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read Committed(已提交读)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个事务能读取到其他事务提交过的数据。&lt;/p&gt;
&lt;p&gt;事务在处理过程中如果重复读取某一个数据，而且这个数据恰好被其他事务修改并提交了， 那么当前重复读取数据的事务就会出现同一个数据前后不同的情况。 已提交读是oracle、pg的默认隔离级别&lt;/p&gt;
&lt;p&gt;在这个隔离级别会发生“不可重复读”和”幻读“的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read Uncommitted(未提交读)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个事务能读取到其他事务修改过，但是还没有提交的(Uncommitted)的数据。&lt;/p&gt;
&lt;p&gt;数据被其他事务修改过，但还没有提交，就存在着回滚的可能性，这时候读取这些“未提交” 数据的情况就是“脏读”。&lt;/p&gt;
&lt;p&gt;在这个隔离级别会发生“脏读”场景。&lt;/p&gt;
&lt;p&gt;pg没有未提交读这个隔离级别，设置未提交读会被当做已提交读&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;标准的一致性读和隔离级别矩阵&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;事务隔离级别&lt;/th&gt;
 &lt;th&gt;脏读&lt;/th&gt;
 &lt;th&gt;不可重复读&lt;/th&gt;
 &lt;th&gt;幻影读&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;未提交读&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;已提交读&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;可重复读&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;序列化&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;pg的一致性度和隔离级别矩阵&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;事务隔离级别&lt;/th&gt;
 &lt;th&gt;脏读&lt;/th&gt;
 &lt;th&gt;不可重复读&lt;/th&gt;
 &lt;th&gt;幻影读&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;未提交读&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;已提交读&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;td&gt;可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;可重复读&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;序列化&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;td&gt;不可能&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 class="relative group"&gt;事务隔离级别的历史
 &lt;div id="事务隔离级别的历史" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e7%9a%84%e5%8e%86%e5%8f%b2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ANSI SQL-92定义的隔离级别和异常现象确实对数据库行业影响深远，甚至30年后的今天，绝大部分工程师对事务隔离级别的概念还停留在此，甚至很多真实的数据库隔离级别实现也停留在此。但后ANSI92时代对事物隔离有许多讨论甚至批评，针对隔离级别和异常现象的论文、博客、文章、讨论非常多，这里概况一下事务的比较重要发展历史：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1992年，由于数据库行业处于混沌的事务状态，美国国家标准学会定义ANSI SQL-92标准。也就是广泛流传的4种隔离级别和4种异常现象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1995年，snapshot isolation等隔离级别提出和更多的异常现象。微软工程师等提出snapshot isolation隔离级别，并对ANSI SQL-92做出批判，92标准定义模糊，而且有许多隔离级别和异常现象未定义。参考&lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf" target="_blank" rel="noreferrer"&gt;《对ANSI SQL隔离级别的批判》&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;此时隔离级别已不止4个，异常现象也更多，其中也包括写偏序异常。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1999年 ，由于锁模式的不同发展出过多的隔离级别，&lt;a href="http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-786.pdf" target="_blank" rel="noreferrer"&gt;Atul Adya的论文&lt;/a&gt;整理了这些现象，并根据异常现象和功能将众多隔离级别回溯到ANSI SQL92标准进行对应。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2005年 ，由于绝大部分数据库声称他们是可串行化的，但他们实际上是快照隔离， Alan Fekete et al 提出&lt;a href="https://pdfs.semanticscholar.org/d658/2728e30011adfe27b329c35203dfb8d1e7a8.pdf" target="_blank" rel="noreferrer"&gt;“使快照隔离可序列化”&lt;/a&gt;。在snapshot isolation级别基础上实现可序列化，消除快照隔离的异象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2008年 ，Fekete 扩展了可序列化，并提出数据库层面实现“使快照隔离可序列化”，称之为&lt;a href="https://cs.nyu.edu/courses/fall09/G22.2434-001/p729-cahill.pdf" target="_blank" rel="noreferrer"&gt;快照隔离可序列化SSI (Serializable Snapshot Isolation) &lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2012年 ，postgresql第一个在数据库中实现SSI ，参考&lt;a href="https://drkp.net/papers/ssi-vldb12.pdf" target="_blank" rel="noreferrer"&gt;postgresql数据库实现SSI的论文&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中，95年《对ANSI SQL隔离级别的批判》中的隔离级别和异常现象



&lt;img src="https://lastdba.com/img/csdn/b45dce972611.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;各种数据库支持的隔离级别
 &lt;div id="各种数据库支持的隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%84%e7%a7%8d%e6%95%b0%e6%8d%ae%e5%ba%93%e6%94%af%e6%8c%81%e7%9a%84%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;很多数据库的声称他们”完全支持ACID“特性，但是没有可串行化是不能完全实现ACID的（特别是一致性）。然而许多数据库在不支持可串行化级别下声称他们支持ACID。其实他们绝大部分都没有完全实现，包括数据库老大哥oracle。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/588a66bd74bb.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;可串行化
 &lt;div id="可串行化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%af%e4%b8%b2%e8%a1%8c%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;人们对可串行化存在许多误解。&lt;/p&gt;
&lt;p&gt;可串行化的含义：如果每个事务本身是正确的，即满足某些完整性条件，那么包括这些事务的任何串行执行的时间表是正确的（其事务仍然满足其条件）：“串行”意味着事务在时间上不重叠，并且不能相互干扰，即彼此之间存在完全隔离。&lt;/p&gt;
&lt;p&gt;1970年代可串行化（serializable）通过严格两阶段锁（SS2PL）实现，读写相互阻塞，直到事务结束。SS2PL丢失高可用性但消除了异常现象。&lt;/p&gt;
&lt;p&gt;除了SS2PL实现可串行化，还有其他方式，比如可串行化快照隔离（SSI）。&lt;/p&gt;
&lt;p&gt;为了保证没有异常，可串行化会丢失一些并发性（不同实现方式有所不同），但可以真正保证数据的一致性（ACID中的consistency）。也就是说没有实现串行化的数据库，其实没有完全支持ACID特性&lt;/p&gt;
&lt;p&gt;可串行化在数学上已经证明可以实现，但是真实的数据库世界有点”不正常“。实际上，可串行化是事务隔离级别中最高级的，也是所有学者和大佬强力推荐的隔离级别，不过绝大部分数据库在RC或快照隔离级别上运行&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么弱隔离级别在学术上有问题，实际上没出现严重问题？
 &lt;div id="为什么弱隔离级别在学术上有问题实际上没出现严重问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e5%bc%b1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e5%9c%a8%e5%ad%a6%e6%9c%af%e4%b8%8a%e6%9c%89%e9%97%ae%e9%a2%98%e5%ae%9e%e9%99%85%e4%b8%8a%e6%b2%a1%e5%87%ba%e7%8e%b0%e4%b8%a5%e9%87%8d%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;1.非可串行化隔离级别的异常现象，一般都需要再高并发情况下才会发生，一般低并发数据库不太会出现问题&lt;/p&gt;
&lt;p&gt;2.异常现象真的发生的时候，有些应用可能没发现异常现象或没检查到异常对他们不重要。&lt;/p&gt;
&lt;p&gt;3.有可能数据异常了，但应用只是返回报错，并进入数据异常处理程序。&lt;/p&gt;
&lt;p&gt;4.成本过高。不仅是数据库序列化隔离级别开发成本高，应用对可序列化也需要适应成本。光是理解这部分复杂的理论就不是一件容易的事&lt;/p&gt;
&lt;p&gt;5.高级别的隔离会丢失一些性能。大量的改造工作可能是吃力不讨好的，应用需要在“高并发”和“无异常现象”间做抉择&lt;/p&gt;
&lt;p&gt;6.业务基于机制开发，而不是规则开发。业务多少有点适应弱隔离级别的异常现象，特别是RC或快照隔离级别&lt;/p&gt;

&lt;h3 class="relative group"&gt;快照隔离
 &lt;div id="快照隔离" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bf%ab%e7%85%a7%e9%9a%94%e7%a6%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ANSI SQL92并未定义快照隔离snapshot isolation(SI)，这个隔离级别随着数据库行业发展才出现。&lt;/p&gt;
&lt;p&gt;引自wiki定义：在快照隔离下执行的事务是在事务开始时拍摄的数据库的快照上操作的。当事务结束时，只有当事务更新的值自快照拍摄以来没有外部更改时，它才会成功提交。这样写冲突将导致事务中止。&lt;/p&gt;
&lt;p&gt;快照隔离级别顾名思义就是就是使用了快照，存在于使用了MVCC的数据库中，多版本并发机制支持用户并发执行事务。&lt;/p&gt;
&lt;p&gt;1992年 ANSI SQL92标准基于数据库的锁而定义，所以没有快照隔离级别这个定义。直到1995年《批判》的出现才被提出。&lt;/p&gt;

&lt;h3 class="relative group"&gt;快照隔离串行化
 &lt;div id="快照隔离串行化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bf%ab%e7%85%a7%e9%9a%94%e7%a6%bb%e4%b8%b2%e8%a1%8c%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于快照隔离的广泛应用，而可序列化是学术上的数据库需要达到的隔离级别目标，可序列化快照隔离Serializable Snapshot Isolation (SSI) 随即产生。顾名思义，在快照隔离的基础上实现可序列化。&lt;/p&gt;
&lt;p&gt;由于ANSI92标准的模糊性，虽然没有定义快照隔离，但许多数据库实际上就是使用的快照隔离。而快照隔离同样存在一些异常现象（包括写偏序），SSI的出现就是为了解决这些异常现象。&lt;/p&gt;
&lt;p&gt;主流数据库通过基于S2PL或MVCC实现并发控制。在S2PL下写操作会阻塞其他事务读写，因此不会有写偏序异常问题。而MVCC实现了读写互不阻塞，只有写写冲突。在并发RW模式模式下会导致写偏序问题。SSI在pg9.1开始已经嵌入快照隔离SI中（pg只有快照隔离，哪怕是在可序列化级别下），解决了写偏序等异常。&lt;/p&gt;

&lt;h3 class="relative group"&gt;写偏序
 &lt;div id="写偏序" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%99%e5%81%8f%e5%ba%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于某些冲突构成环，会出现串行化异常**。**其中比较容易理解的一个就是写偏序(write skew)。&lt;/p&gt;
&lt;p&gt;写偏序只发生在rw模型，ww、wr均不会发生写偏序，并且事务必须在并发条件下才会出现。前一个事务写入依赖后一个事务写入才会形成依赖环。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2e661194aa05.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;有许多现实案例可以出现写偏序异常，我们用一个经典的&lt;strong&gt;黑白球问题&lt;/strong&gt;来理解写偏序&lt;/p&gt;
&lt;p&gt;袋中有10个球，5个白球和5个黑球。此时有两个事务，P和Q。P将所有黑球改成白球，Q将所有白球改成黑球。此时可以有两个串行执行，P，Q或Q，P。在这两种情况下，最终结果是袋中有10个白球或者10个黑球。但是，快照隔离允许另一种结果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务 P 拿出5个黑球&lt;/li&gt;
&lt;li&gt;事务 Q 拿出5个白球&lt;/li&gt;
&lt;li&gt;事务 P 将手中所有黑球改成白球，放回袋中&lt;/li&gt;
&lt;li&gt;事务 Q 将手中所有白球改成黑球，放回袋中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时袋中还是5个黑球和5个白球，这在任何一个串行执行中都是不可能的。但这在快照隔离中是有效：每个事务都维护数据库的一致视图，并且其写集不与任何并发事务的写集重叠，如此白球黑球发生交换。&lt;/p&gt;
&lt;p&gt;黑白球问题说明：快照隔离执行结果与串行化执行结果不一致，快照隔离下发生写偏序异常，数据结果与预期不一致。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg中的SSI
 &lt;div id="pg中的ssi" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e4%b8%ad%e7%9a%84ssi" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;postgresql数据库是首个在数据库中实现SSI的数据库。&lt;/p&gt;
&lt;p&gt;引用wiki的黑白球代码示例&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; dots
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id int &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color text &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; dots
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; x(id) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id, &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; id &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;black&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;white&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; x;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;set default_transaction_isolation = &amp;lsquo;serializable&amp;rsquo;;&lt;/th&gt;
 &lt;th style="text-align: left"&gt;set default_transaction_isolation = &amp;lsquo;serializable&amp;rsquo;;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;begin; &lt;br /&gt;update dots set color = &amp;lsquo;black&amp;rsquo; where color = &amp;lsquo;white&amp;rsquo;;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;begin; &lt;br /&gt; update dots set color = &amp;lsquo;white&amp;rsquo; where color = &amp;lsquo;black&amp;rsquo;;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;commit&lt;/td&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;commit&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;&lt;em&gt;(pg SSI先提交者成功提交，后提交者抛出报错 )&lt;/em&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;ERROR: could not serialize access due to read/write dependencies among transactions DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt. HINT: The transaction might succeed if retried.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（已提交读和可重复读级别，均不会出现报错，黑白球颜色交换，不再展示测试结果）&lt;/p&gt;
&lt;p&gt;严格两阶段提交（S2PL）也可以实现可串行化，但S2PL需要很重的读写锁，直到事务提交为止。S2PL会极大的影响并发性能，而且用户一般不会接受读写互相阻塞的情况，所以pg没有采用S2PL。&lt;/p&gt;
&lt;p&gt;SSI是可序列化的另一种方案。它仍然会使用快照隔离，只是会额外检查是否有异常现象发生。&lt;/p&gt;
&lt;p&gt;两个方案的处理方式也不同：在异常现象发生时，S2PL会阻塞事务，而SSI会中断事务以打破循环。&lt;/p&gt;
&lt;p&gt;人们没有使用可串行化，原因之一有可串行化会降低数据库性能。这其实可以理解，因为有”检查异常现象“的SSI必定比什么检查都没有的弱隔离级别性能低。不过经过SSI实现理论的发展和pg本身对只读事务的优化，SSI的性能已于SI相差无几。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7d32ee35fdba.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;可序列化能极大的简化应用对一致性的担心，而pg9.1已实现ssi并加以优化。期待应用有一天真的能使用可串行化隔离级别。&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务隔离级别参考
 &lt;div id="事务隔离级别参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/SSI" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/SSI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Serializability" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Serializability&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Snapshot_isolation" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Snapshot_isolation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://justinjaffray.com/what-does-write-skew-look-like/" target="_blank" rel="noreferrer"&gt;https://justinjaffray.com/what-does-write-skew-look-like/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.bailis.org/blog/when-is-acid-acid-rarely/" target="_blank" rel="noreferrer"&gt;http://www.bailis.org/blog/when-is-acid-acid-rarely/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf" target="_blank" rel="noreferrer"&gt;https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf&lt;/a&gt; 95年SI隔离级别以及对SQL92标准的批评&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cse.iitb.ac.in/infolab/Data/Courses/CS632/2009/Papers/p492-fekete.pdf" target="_blank" rel="noreferrer"&gt;https://www.cse.iitb.ac.in/infolab/Data/Courses/CS632/2009/Papers/p492-fekete.pdf&lt;/a&gt; SSI论文&lt;/p&gt;
&lt;p&gt;&lt;a href="https://drkp.net/papers/ssi-vldb12.pdf" target="_blank" rel="noreferrer"&gt;https://drkp.net/papers/ssi-vldb12.pdf&lt;/a&gt; postgresql实现SSI&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ristret.com/s/f643zk/history_transaction_histories" target="_blank" rel="noreferrer"&gt;https://ristret.com/s/f643zk/history_transaction_histories&lt;/a&gt; 事务隔离级别的历史&lt;/p&gt;

&lt;h2 class="relative group"&gt;事务的处理
 &lt;div id="事务的处理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%a4%84%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;事务块
 &lt;div id="事务块" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e5%9d%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;从事务形态划分可分为隐式事务和显示事务。隐式事务是一个独立的SQL语句，执行完成后默认提交。显示事务需要显示声明一个事务，多个sql语句组合到一起称为一个事务块。&lt;/p&gt;
&lt;p&gt;事务块通过&lt;code&gt;begin&lt;/code&gt;，&lt;code&gt;begin transaction&lt;/code&gt;，&lt;code&gt;start transaction&lt;/code&gt;开始&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;COMMIT&lt;/code&gt;,&lt;code&gt;END&lt;/code&gt;或&lt;code&gt;ABORT&lt;/code&gt;,&lt;code&gt;ROLLBACK&lt;/code&gt;结束，其中&lt;code&gt;COMMIT=END&lt;/code&gt;，&lt;code&gt;ABORT=ROLLBACK&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;limit&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;END&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果事务块执行过程中一旦有报错，由于事务必须满足原子性，事务只能回退&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: relation &lt;span style="color:#e6db74"&gt;&amp;#34;lzl2&amp;#34;&lt;/span&gt; does &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; exist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LINE &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;^&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=!#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;事务处理函数
 &lt;div id="事务处理函数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e5%a4%84%e7%90%86%e5%87%bd%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务处理函数分为3个层次：顶层事务函数、中层事务函数、底层事务函数
顶层事务函数，处理事务块命令，比如&lt;code&gt;BEGIN&lt;/code&gt;, &lt;code&gt;COMMIT&lt;/code&gt;, &lt;code&gt;ROLLBACK&lt;/code&gt;, &lt;code&gt;SAVEPOINT&lt;/code&gt;等，有如下函数&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;BeginTransactionBlock&lt;/th&gt;
 &lt;th&gt;启动事务块&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;EndTransactionBlock&lt;/td&gt;
 &lt;td&gt;结束事务块&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UserAbortTransactionBlock&lt;/td&gt;
 &lt;td&gt;用户显示结束事务块&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;DefineSavepoint&lt;/td&gt;
 &lt;td&gt;生成保存点&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;RollbackToSavepoint&lt;/td&gt;
 &lt;td&gt;回滚到某保存点&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ReleaseSavepoint&lt;/td&gt;
 &lt;td&gt;释放保存点&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;中层事务函数，每个sql在执行前后都会调用中层事务函数，包括检测到异常后，有如下函数&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;StartTransactionCommand&lt;/th&gt;
 &lt;th&gt;启动事务命令&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;CommitTransactionCommand&lt;/td&gt;
 &lt;td&gt;完成事务命令，注意不是提交命令&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;AbortCurrentTransaction&lt;/td&gt;
 &lt;td&gt;退出当前事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;底层事务函数，真正的事务处理函数，负责维护事务状态、事务资源分配和回收等，有如下函数&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;StartTransaction&lt;/th&gt;
 &lt;th&gt;启动事务&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;CommitTransaction&lt;/td&gt;
 &lt;td&gt;提交事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;AbortTransaction&lt;/td&gt;
 &lt;td&gt;回滚/中断事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CleanupTransaction&lt;/td&gt;
 &lt;td&gt;清理事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;StartSubTransaction&lt;/td&gt;
 &lt;td&gt;启动子事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CommitSubTransaction&lt;/td&gt;
 &lt;td&gt;提交子事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;AbortSubTransaction&lt;/td&gt;
 &lt;td&gt;回滚/中断子事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CleanupSubTransaction&lt;/td&gt;
 &lt;td&gt;清理子事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;其实这上面几个函数还是比较好分辨的。抛开几个特殊的函数（上层相关&lt;code&gt;savepoint&lt;/code&gt;，中层&lt;code&gt;abort&lt;/code&gt;函数），其实上、中、下三层事务层分成了：*Block（事务块函数），*Command（command函数），*Transaction（真正的事务处理函数）。然后把&lt;code&gt;savepoint&lt;/code&gt;子事务当做事务块函数（后面会介绍，子事务可以在事务块中回退，所以这里把子事务放在事务块一级理所当然），把&lt;code&gt;abort&lt;/code&gt;命令当做command级函数就可以了。&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务块状态
 &lt;div id="事务块状态" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e5%9d%97%e7%8a%b6%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;上层函数和中层函数同时控制事务块状态，底层函数控制事务状态&lt;/p&gt;
&lt;p&gt;事务块状态和事务状态均在&lt;code&gt;src/backend/access/transam/xact.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; TBlockState
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 不在事务块中的状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_DEFAULT, &lt;span style="color:#75715e"&gt;/* 空闲状态，事务开始或结束后都处于此状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_STARTED, &lt;span style="color:#75715e"&gt;/* 刚开始进入事务块时的状态，由TBLOCK_DEFAULT转换到此状态，此状态存在时间较短 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 事务块状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_BEGIN, &lt;span style="color:#75715e"&gt;/* 启动事务块，此时才启动数据块，进入数据块级状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_INPROGRESS, &lt;span style="color:#75715e"&gt;/* 活跃的事务，BEGIN以后事务块一直处于此状态，直到事务结束 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_IMPLICIT_INPROGRESS, &lt;span style="color:#75715e"&gt;/* 隐式BEGIN的活跃事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_PARALLEL_INPROGRESS, &lt;span style="color:#75715e"&gt;/* 并行执行的活跃事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_END, &lt;span style="color:#75715e"&gt;/* 收到COMMIT命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_ABORT, &lt;span style="color:#75715e"&gt;/* 事务失败，等待ROLLBACK */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_ABORT_END, &lt;span style="color:#75715e"&gt;/* 事务失败，收到ROLLBACK */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_ABORT_PENDING, &lt;span style="color:#75715e"&gt;/* 活跃事务，收到ROLLBACK */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_PREPARE, &lt;span style="color:#75715e"&gt;/* 活跃事务，收到PREPARE（显式2PC） */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 子事务状态（仍然是事务块级状态） */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBBEGIN, &lt;span style="color:#75715e"&gt;/* 启动子事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBINPROGRESS, &lt;span style="color:#75715e"&gt;/* 活跃的子事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBRELEASE, &lt;span style="color:#75715e"&gt;/* 收到RELEASE（释放保存点） */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBCOMMIT, &lt;span style="color:#75715e"&gt;/* 当子事务还在运行的时候（SUBINPROGRESS），收到父事务COMMIT */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBABORT, &lt;span style="color:#75715e"&gt;/* 失败子事务，等待rollback命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBABORT_END, &lt;span style="color:#75715e"&gt;/* 失败子事务，收到rollback命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBABORT_PENDING, &lt;span style="color:#75715e"&gt;/* 活跃子事务，收到rollback命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBRESTART, &lt;span style="color:#75715e"&gt;/* 活跃子事务，收到rollback to命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TBLOCK_SUBABORT_RESTART &lt;span style="color:#75715e"&gt;/* 失败子事务，收到ROLLBACK TO命令 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} TBlockState;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;大部分状态是显而易见的。需要补充说明的是事务回滚（rollback）和事务失败(ABORT)两者后续行为是相似的，他们都要把清理事务资源和退出当前事务。但是pg把他们分为了两种行为，设置了两种状态&lt;code&gt;TBLOCK_ABORT&lt;/code&gt;，&lt;code&gt;TBLOCK_ABORT_END&lt;/code&gt;（子事务亦然），为什么会这样呢？&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;src/backend/access/transam/README&lt;/code&gt;中对此现象作了详细的说明：&lt;/p&gt;
&lt;blockquote&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;场景 1&lt;/th&gt;
 &lt;th&gt;场景 2&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1) 用户输入 &lt;code&gt;BEGIN&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;1) 用户输入 &lt;code&gt;BEGIN&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2) 用户执行某些命令&lt;/td&gt;
 &lt;td&gt;2) 用户执行某些命令&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3) 用户不喜欢她所看到的东西，输入&lt;code&gt;ABORT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;3) 事务系统因为某些原因中断（语法错误等）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;场景1中，我们想中断事务并把事务回退到default状态 。&lt;/p&gt;
&lt;p&gt;场景2中，可能后续还会有更多的命令，这些命令也是当前事务块的一部分，我们不得不忽略这些命令，直到我们看见&lt;code&gt;COMMIT&lt;/code&gt; or &lt;code&gt;ROLLBACK&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AbortCurrentTransaction&lt;/code&gt;处理事务内部中断，&lt;code&gt;UserAbortTransactionBlock&lt;/code&gt;处理事务用户中断。两个函数都依赖&lt;code&gt;AbortTransaction&lt;/code&gt;来处理所有真正的工作。唯一区别在于&lt;code&gt;AbortTransaction&lt;/code&gt;工作结束后我们进入了什么状态:&lt;/p&gt;
&lt;p&gt;* AbortCurrentTransaction leaves us in TBLOCK_ABORT&lt;/p&gt;
&lt;p&gt;* UserAbortTransactionBlock leaves us in TBLOCK_ABORT_END（&lt;em&gt;原文如此，不过用户输入结束应该进入TBLOCK_ABORT_PENDING状态&lt;/em&gt;）&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;底层事务中断处理分为两个阶段：&lt;/p&gt;
&lt;p&gt;* 一旦我们意识到事务失败，就会执行&lt;code&gt;AbortTransaction&lt;/code&gt;。这应该释放所有共享资源（锁等），以防不必要的增加其他backends的延迟。&lt;/p&gt;
&lt;p&gt;* 当我最终看到用户&lt;code&gt;COMMIT&lt;/code&gt;或者&lt;code&gt;ROLLBACK&lt;/code&gt;时，执行&lt;code&gt;CleanupTransaction&lt;/code&gt;；该函数将清理资源并让我们完全跳出事务。特别是，在此之前我们不能破坏&lt;code&gt;TopTransactionContext&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 class="relative group"&gt;事务状态
 &lt;div id="事务状态" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%8a%b6%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务状态一目了然(注意跟事务块状态是不同的)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; TransState
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_DEFAULT, &lt;span style="color:#75715e"&gt;/* 空闲 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_START, &lt;span style="color:#75715e"&gt;/* 事务启动 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_INPROGRESS, &lt;span style="color:#75715e"&gt;/* 活跃的事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_COMMIT, &lt;span style="color:#75715e"&gt;/* 事务提交 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_ABORT, &lt;span style="color:#75715e"&gt;/* 退出事务 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TRANS_PREPARE &lt;span style="color:#75715e"&gt;/* prepare事务（2pc） */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} TransState;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;事务状态流转
 &lt;div id="事务状态流转" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%8a%b6%e6%80%81%e6%b5%81%e8%bd%ac" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务块中的一个个命令，调用事务函数，事务函数转变事务、事务块的状态
以一个最简单的事务块举例（参考readme）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; foo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; foo &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;命令调用关系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 	/ StartTransactionCommand; --中层事务命令启动函数
 / StartTransaction; --底层真正处理启动事务函数
1)&amp;lt; ProcessUtility; --ProcessUtility处理BEGIN命
 \ BeginTransactionBlock; --顶层事务块启动函数
 \ CommitTransactionCommand; --中层完成命令函数 
 		 
 / StartTransactionCommand; --中层事务命令启动函数
2) / PortalRunSelect; --SELECT语句执行
 \ CommitTransactionCommand; --中层完成命令函数
 \ CommandCounterIncrement; --中层完成命令函数
 
 / StartTransactionCommand; --中层事务命令启动函数
3) / ProcessQuery; --INSERT语句执行
 \ CommitTransactionCommand; --中层完成命令函数
 \ CommandCounterIncrement; --命令计数器计数+1

 / StartTransactionCommand; --中层事务命令启动函数
 / ProcessUtility; --ProcessUtility处理commit命令
 4) &amp;lt; EndTransactionBlock; --调用顶层事务块结束函数
 \ CommitTransactionCommand; --中层完成命令函数
 \ CommitTransaction; --底层真正处理提交事务函数
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;事务块的每一个命令，都会以中层函数&lt;code&gt;StartTransactionCommand&lt;/code&gt;和&lt;code&gt;CommitTransactionCommand&lt;/code&gt;开始和结束&lt;/li&gt;
&lt;li&gt;在以上两个中层函数中间，可以看成真正执行的命令处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2)SELECT和3)INSERT事务块状态都是&lt;code&gt;TBLOCK_INPROGRESS&lt;/code&gt;，&lt;code&gt;BEGIN&lt;/code&gt;和&lt;code&gt;COMMIT&lt;/code&gt;状态块转换流程如下：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b8f307da3f3f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务函数参考
 &lt;div id="事务函数参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e5%87%bd%e6%95%b0%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;《postgresql技术内幕》
src/backend/access/transam/README&lt;/p&gt;

&lt;h2 class="relative group"&gt;事务ID
 &lt;div id="事务id" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg中每个事务都会分配事务ID，事务ID分为虚拟事务ID和持久化事务ID。pg的事务ID非常重要，是理解事务、数据可见性、事务ID回卷等等的重要知识点。&lt;/p&gt;

&lt;h3 class="relative group"&gt;虚拟事务ID
 &lt;div id="虚拟事务id" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%99%9a%e6%8b%9f%e4%ba%8b%e5%8a%a1id" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;只读事务不会分配事务ID，事务ID是很宝贵的资源，比如简单的select语句不会申请事务ID。本身不需要把事务ID持久化到磁盘，但是为了在共享锁等情况下对事务进行标识，需要一种非持久化的事务ID，这个就是虚拟事务ID（vxid)
VXID由两部分组成：backendID 和backend本地计数器。
源码：&lt;code&gt;src/include/storage/lock.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BackendId backendId; &lt;span style="color:#75715e"&gt;/* backendId from PGPROC */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LocalTransactionId localTransactionId; &lt;span style="color:#75715e"&gt;/* lxid from PGPROC */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} VirtualTransactionId;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(PGPROC是一种存储进程信息的结构体，后面会介绍）&lt;/p&gt;
&lt;p&gt;pg_locks可以看到vxid，查询pg_locks本身就是一个sql，会产生vxid&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,virtualxid,virtualtransaction,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualtransaction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+------------+--------------------+-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation		&lt;span style="color:#f92672"&gt;|&lt;/span&gt; 		 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; 	 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; savepoint p1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SAVEPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,virtualxid,virtualtransaction,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype 	&lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualtransaction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+------------+--------------------+-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation 	&lt;span style="color:#f92672"&gt;|&lt;/span&gt; 		 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,virtualxid,virtualtransaction,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype 	&lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualtransaction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+------------+--------------------+-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation 	&lt;span style="color:#f92672"&gt;|&lt;/span&gt; 	 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时\q退出会话再立即登录，计数仍然继续4/19&lt;/p&gt;
&lt;p&gt;另开一个窗口，backendID+1&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,virtualxid,virtualtransaction,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; virtualtransaction &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+------------+--------------------+-----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessShareLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; virtualxid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ExclusiveLock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;从以上测试能看出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VXID的backendID不是真正的进程号PID，也只是一个简单的递增的编号&lt;/li&gt;
&lt;li&gt;VXID的bakendID和命令编号都是递增的&lt;/li&gt;
&lt;li&gt;子事务没有自己的VXID，他们用父事务的VXID&lt;/li&gt;
&lt;li&gt;VXID也有回卷，不过问题不严重，因为没有持久化，实例重启后VXID从头开始计数&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;永久事务ID
 &lt;div id="永久事务id" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b0%b8%e4%b9%85%e4%ba%8b%e5%8a%a1id" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;32位的TransactionId
 &lt;div id="32位的transactionid" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#32%e4%bd%8d%e7%9a%84transactionid" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;当发生数据变化的事务开始时，事务管理器会为事务分配一个唯一标识&lt;code&gt;TransactionId&lt;/code&gt;。&lt;code&gt;TransactionId&lt;/code&gt;是32位无符号整型，总共可以存储 &lt;code&gt;2^32=4294967296&lt;/code&gt;，42亿多个事务。32位无符号整型能存储的数据范围为：&lt;code&gt;0~2^32-1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3个特殊的事务ID&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;src/include/access/transam.h中宏定义几个事务ID&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define InvalidTransactionId ((TransactionId) 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define BootstrapTransactionId ((TransactionId) 1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define FrozenTransactionId ((TransactionId) 2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define FirstNormalTransactionId ((TransactionId) 3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MaxTransactionId ((TransactionId) 0xFFFFFFFF)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;0 代表无效TransactionID&lt;/p&gt;
&lt;p&gt;1 代表启动事务ID，只在初始化数据库时才会使用。比所有正常事务都旧&lt;/p&gt;
&lt;p&gt;2 代表冻结事务ID。比所有正常事务都旧&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdIsNormal(xid) ((xid) &amp;gt;= FirstNormalTransactionId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;事务ID&amp;gt;=3时是正常事务id。&lt;/p&gt;
&lt;p&gt;最大事务ID MaxTransactionId是0xFFFFFFFF=4294967295=2^32-1
所以正常事务id能分配到的范围为:3~2^32-1&lt;/p&gt;

&lt;h4 class="relative group"&gt;64位的FullTransactionId
 &lt;div id="64位的fulltransactionid" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#64%e4%bd%8d%e7%9a%84fulltransactionid" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;事务ID是顺序递增的，PostgreSQL一直使用32位事务ID。在PostgreSQL 7.2之前，当32位事务ID用完时，必须dump然后恢复数据库。而64位的事务ID几乎是用不完的。源码中定义64位&lt;code&gt;FullTransactionId&lt;/code&gt;为结构体&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *一个64位的值，包含一个epoch和一个TransactionId。它被封装在一个结构中，以防止隐式转换为TransactionId。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *并非所有值都表示有效的正常XID。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; FullTransactionId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uint64 value;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} FullTransactionId;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由上面的源码可知，64位的由&lt;code&gt;epoch&lt;/code&gt;和32位的&lt;code&gt;TransactionId&lt;/code&gt;组成，通过以下函数转化&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define EpochFromFullTransactionId(x)	((uint32) ((x).value &amp;gt;&amp;gt; 32))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XidFromFullTransactionId(x)		((uint32) (x).value)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;epoch是&lt;code&gt;FullTransactionId&lt;/code&gt;右移32位，xid（&lt;code&gt;TransactionId&lt;/code&gt;）是&lt;code&gt;FullTransactionId&lt;/code&gt;取模。这相当于把32位的&lt;code&gt;TransactionId&lt;/code&gt;看成“环”，循环重复使用；64位的&lt;code&gt;FullTransactionId&lt;/code&gt;是一直递增的“线”，几乎取不完。&lt;/p&gt;
&lt;p&gt;full的事务id可以超过2^32：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e91011271323.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务ID分配
 &lt;div id="事务id分配" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e5%88%86%e9%85%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;做几个小实验来看下事务id是怎么分配的。其中用到两个返回事务id的function&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg_current_xact_id ()&lt;/code&gt;：返回当前事务id，如果当前事务还没有分配事务id，那么分配一个事务id。pg12及以前用&lt;code&gt;txid_current ()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg_current_xact_id_if_assigned ()&lt;/code&gt; ：返回当前事务id，如果当前事务还没有分配事务id，那么返回NULL。pg12及以前用&lt;code&gt;txid_current_if_assigned () &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;事务id顺序分配&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# select pg_current_xact_id();
 pg_current_xact_id 
--------------------
 612
lzldb=# select pg_current_xact_id();
 pg_current_xact_id 
--------------------
 613
lzldb=# select pg_current_xact_id();
 pg_current_xact_id 
--------------------
 614&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;begin不会立即分配事务id&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;lzldb=# begin; --显示开启事务
BEGIN
lzldb=*# select pg_current_xact_id_if_assigned () ; --begin不会立即分配事务id
 pg_current_xact_id_if_assigned 
-------------------------------- 

(1 row)
lzldb=*# select * from lzl1; --begin后立即查询
 a 
---

(0 rows)
lzldb=*# select pg_current_xact_id_if_assigned () ; --查询不会分配事务id
 pg_current_xact_id_if_assigned 
-------------------------------- 

(1 row)
lzldb=*# insert into lzl1 values(1); --插入数据，做一个数据变更
INSERT 0 1
lzldb=*# select pg_current_xact_id_if_assigned () ; --begin后的第一个非查询语句分配事务id
 pg_current_xact_id_if_assigned 
--------------------------------
 611
lzldb=*# commit;
COMMIT
lzldb=# select xmin, pg_current_xact_id_if_assigned () from lzl1; --insert事务写入到xmin
 xmin | pg_current_xact_id_if_assigned 
------+--------------------------------
 611 &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;系统表中的有些记录，在数据库初始化时分配了BootstrapTransactionId=1&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sqlite" data-lang="sqlite"&gt;postgres=# select xmin,count(*) from pg_class where xmin=1 group by xmin;
 xmin | count 
------+-------
 1 | 184&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;以上实验得出以下结论&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库初始化时分配特殊事务id 1，可以在系统表中看到&lt;/li&gt;
&lt;li&gt;事务id是递增分配的&lt;/li&gt;
&lt;li&gt;begin不会立即分配事务id，begin后的第一个非查询语句分配事务id&lt;/li&gt;
&lt;li&gt;当一个事务插入了一tuple后，会将事务的txid写入这个tuple的xmin。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;事务ID对比
 &lt;div id="事务id对比" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e5%af%b9%e6%af%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg事务新旧通过事务ID来对比。在&lt;code&gt;src/backend/access/transam/transam.c&lt;/code&gt;定义了4种事务ID对比函数，分别是&amp;lt;,&amp;lt;=,&amp;gt;,&amp;gt;=&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdPrecedes&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdPrecedesOrEquals&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdFollows&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionIdFollowsOrEquals&lt;/span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;内容都差不多，拿&lt;code&gt;TransactionIdPrecedes()&lt;/code&gt;代表来看&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdPrecedes&lt;/span&gt;(TransactionId id1, TransactionId id2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * If either ID is a permanent XID then we can just do unsigned
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * comparison. If both are normal, do a modulo-2^32 comparison.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;int32 diff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(id1) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(id2))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (id1 &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; id2);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;diff &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (int32) (id1 &lt;span style="color:#f92672"&gt;-&lt;/span&gt; id2);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (diff &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;该段源码的知识点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TransactionIdIsNormal()&lt;/code&gt;是已经在header中宏定义了的判断正常事务的函数，FirstNormalTransactionId是常量3。也就是说正常事务ID是&amp;gt;=3的&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdIsNormal(xid) ((xid) &amp;gt;= FirstNormalTransactionId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;int32是有符号的整型，第一位0表示正数，第一位-1表示负数，取值范围-2*31~2^31-1&lt;/li&gt;
&lt;li&gt;数值溢出，意思数值超过数据存储范围，比如2^31对于int32是刚好数值溢出的。为了保证数据在范围内，对数值加减模长&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对比事务ID源码分为2段理解&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;非正常事务ID对比：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(id1) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(id2))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (id1 &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; id2);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当id1=2，id2=100时，return(2&amp;lt;100)，precede为真，正常事务较新&lt;/p&gt;
&lt;p&gt;当id1=100，id2=2时，return (100&amp;lt;2)，precede为假，正常事务较新&lt;/p&gt;
&lt;p&gt;所以，txid为1、2时比正常事务要旧&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正常事务ID对比：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;diff &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (int32) (id1 &lt;span style="color:#f92672"&gt;-&lt;/span&gt; id2);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (diff &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;id1-id2可以是负数，所以diff不能是unsign int，转换有符号型的int。然后最关键的来了&lt;/p&gt;
&lt;p&gt;由于int32是-2*31~2^31-1，&lt;/p&gt;
&lt;p&gt;当id1=&lt;code&gt;2^31+99&lt;/code&gt;，id2=100，id1-id2=&lt;code&gt;2^31-1&lt;/code&gt;。这没问题，int32刚好可以存放 =&amp;gt;大txid较新&lt;/p&gt;
&lt;p&gt;当id1=&lt;code&gt;2^31+100&lt;/code&gt;，id2=100，id1-id2=&lt;code&gt;2^31&lt;/code&gt;。这有问题，刚好超出int32存储范围，此时的值为&lt;code&gt;2^31-2^32=-2^31&lt;/code&gt;&amp;lt;0 =&amp;gt;小txid较新&lt;/p&gt;
&lt;p&gt;当id1=100，id2=&lt;code&gt;2^31+100&lt;/code&gt;，id1-id2=&lt;code&gt;-2^31&lt;/code&gt;。这没问题，int32刚好可以存放 =&amp;gt;大txid较新&lt;/p&gt;
&lt;p&gt;当id1=100，id2=&lt;code&gt;2^31+101&lt;/code&gt;，id1-id2=&lt;code&gt;-2^31-1&lt;/code&gt;。这有问题，刚好超出int32存储范围，此时的值为&lt;code&gt;-2^31-1+2^32=2^31-1&lt;/code&gt;&amp;gt;0 =&amp;gt;小txid较新&lt;/p&gt;
&lt;p&gt;以上分析可以看出，当发生数值溢出时，txid大的事务看不见更小的txid事务，本身数值溢出是一个异常事件，这无可厚非。为了解决这个问题，pg将40亿事务id分成两半，一半事务是可见的，另一半事务是不可见的。&lt;/p&gt;
&lt;p&gt;比如，txid 100的事务，它过去的20亿事务是它可见的，它未来的20亿事务是它不可见的。所以，在pg数据库中最大事务和最小事务（数据库年龄）之差最大为&lt;code&gt;|-2^31|=2^31&lt;/code&gt;，20亿左右&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b39c0f44d535.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务ID回卷
 &lt;div id="事务id回卷" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e5%9b%9e%e5%8d%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是事务ID回卷&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;理解事务ID回卷本身不难，但是刚开始了解回卷时，发现了事务ID回卷有两种定义：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg官方定义：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于事务ID的大小有限（32位），一个长时间运行的集群（超过40亿个事务）将遭遇事务ID的回卷：XID计数器回卷到零，突然之间，过去的事务似乎在未来，这意味着它们变得不可见。简而言之，就是灾难性的数据丢失。（事实上，数据仍然存在，但如果你无法获得数据。）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;interdb解释：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;元组中t_xmin记录了当前元组的最小事务，如果这个元组一直没有变化，这个t_xmin不会变。假如一个元组tuple_1由txid=100事务创建，它的t_xmin=100。如果数据库事务向前推进了&lt;code&gt;2^31&lt;/code&gt;个，到了&lt;code&gt;2^31+100&lt;/code&gt;，此时tuple_1是可见的。此时再启动一个事务，txid推进至&lt;code&gt;2^31+101&lt;/code&gt;，txid=100的事务属于未来，tuple_1是不可见的，此时便发生了严重的数据丢失问题，这就是事务回卷。&lt;/p&gt;
&lt;p&gt;是的，对事物回卷的定义，官方文档与有些经典文章不太一样，他俩确实是在说两个事情。我把这个当成是&lt;strong&gt;翻译问题&lt;/strong&gt;：他俩的行为在英语语义里面都是&lt;strong&gt;wraparound&lt;/strong&gt;。如果重新思考“&lt;strong&gt;回卷&lt;/strong&gt;”（&lt;strong&gt;wraparound&lt;/strong&gt;）的含义，其实它俩都是回卷。&lt;/p&gt;
&lt;p&gt;不过回卷形式还是有些区别：前者是事务ID（&lt;code&gt;2^32&lt;/code&gt;）全部用完，回卷到0重新计数；后者是把事务ID分成两半，“最老的事务ID“与”最新的事务ID“只差大于&lt;code&gt;2^31&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg官方定义的事务id回卷是为了引出“事务ID是一个环”这个概念&lt;/li&gt;
&lt;li&gt;一般认为的事务id回卷问题 ，是“把环分成两半，一半为可见，一半为不可见”这个概念，出现“超过一半”的事务id就是事务id回卷&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上真正需要关心的回卷问题是后者：最新和最旧的事务id相差不能超过21亿（&lt;code&gt;2^31&lt;/code&gt;)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;21亿事务到底要跑多久&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;21亿个事务看上去是挺多，但是仍然可能用完。&lt;/p&gt;
&lt;p&gt;比如一个tps为100的pg库（不算select语句，因为单纯的select不会分配事务id），1天会使用8640000个事务，只需要历时2147483648/8640000≈248天就可以把21亿个事务id耗尽发生事务回卷；如果每秒1000个事务，不到1个月时间就可以把21亿事务id用完。所以事务回卷问题是pg数据库中必须要关注的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务id冻结
 &lt;div id="事务id冻结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e5%86%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;为了解决事务回卷引起严重的数据丢失问题，pg引入事务冻结的概念。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/203cfe4768b1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;xid会循环使用，并分成2半，一半可见一半不可见。如xid=100的元组，如果不经过任何操作，事务id一直往前推进，那么这个可见的元组最终将不可见。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7512304ffdf5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;之前介绍有个冻结事务id，此时给xid=100的元组标记为冻结事务id，那么他将仍然可见。&lt;/p&gt;
&lt;p&gt;这个就是事务冻结的作用。&lt;/p&gt;
&lt;p&gt;事务id FrozenTransactionIdn=2，并且比所有正常事务都旧。也就是说txid=2对于所有正常事务(txid&amp;gt;=3)都是可见的。当t_xmin比当前txid-vacuum_freeze_min_age(默认5000w）更旧时，该元组将重写为冻结事务id 2。在9.4及以后的版本，用t_infomask中的xmin_frozen来表示冻结元组，而不是重写t_xmin为2。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/352182ad7218.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;事务ID回卷问题有许多优化方案，不过都绕不过事务冻结处理回卷问题，而事务冻结这个操作,会有非常大的IO消耗以及cpu消耗(所有表的所有行读一遍,重置标记)无从避免回卷，甚至数据库会拒绝所有操作，直至冻结操作结束，这也是俗称的“冻结炸弹”。业务系统越繁忙，事务越多的库,越容易触发。（后面再开章节展开事务冻结优化）&lt;/p&gt;

&lt;h3 class="relative group"&gt;64位的事务id
 &lt;div id="64位的事务id" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#64%e4%bd%8d%e7%9a%84%e4%ba%8b%e5%8a%a1id" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务id耗尽回卷问题&lt;strong&gt;终极解决方案&lt;/strong&gt;就是使用64位的事务ID。32位事务id有&lt;code&gt;2^32&lt;/code&gt;个，64位事务id有&lt;code&gt;2^64&lt;/code&gt;个。即使每秒10000个事务，每天864000000个事务，也要5849万年才能把事务id消耗光。如果拥有64位事务id，事务id几乎是取之不尽用之不竭，就不需要考虑事务id回卷问题，也不需要事务冻结操作，也就没有“冻结炸弹”的概念&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么还没有实现64位事务id？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;请注意，64为事务id已经在pg库中了（就像前面介绍的FullTransactionId）。但因为元组存储结构有限，元组中的xmin、xmax等等仍然用的是32位的XID，事务id对比大小仍然依赖32位的XID。xmin，xmax可以简单理解为插入事务和删除事务的事务id，保存在每个元组的header中（元组结构章节将介绍该部分内容），而header空间是有限的。32位事务id有8个字节，64位事务有16个字节，存储xmin、xmax两个事务id将需要额外的16字节空间，目前header无法保存这么大的数据。社区讨论过两种实现方案&lt;/p&gt;
&lt;p&gt;1.扩展header。直接将64位事务id存储进去&lt;/p&gt;
&lt;p&gt;2.header大小不变。内存中保留64位事务id，增加epoch概念来位移转换两者的关系。&lt;/p&gt;
&lt;p&gt;第一种方案已基本放弃，对比其他系统，pg的tuple header已经够大了。&lt;/p&gt;
&lt;p&gt;第二种方案epoch已经有了，fulltransactionid转换transactionid已经有了，怎么把元组中的transactionid转换为fulltransactionid是关键（不过怎么也得多一些存储来保存epoch吧，不然怎么实现？）&lt;/p&gt;
&lt;p&gt;参考社区邮件&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/CAEYLb_UfC&amp;#43;HZ4RAP7XuoFZr&amp;#43;2_ktQmS9xqcQgE-rNf5UCqEt5A@mail.gmail.com" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/message-id/CAEYLb_UfC+HZ4RAP7XuoFZr+2_ktQmS9xqcQgE-rNf5UCqEt5A@mail.gmail.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/flat/DA1E65A4-7C5A-461D-B211-2AD5F9A6F2FD@gmail.com" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/message-id/flat/DA1E65A4-7C5A-461D-B211-2AD5F9A6F2FD%40gmail.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2014年社区就提出了64位事务永久解决freeze问题，并于2017年开始讨论如何实践64位事务id，不过经过了多个pg版本也只是只闻其声不见其人。由于数据库对于数据的敏感性和重要性，而事务id的改造对于数据库来说牵扯的东西太多，稍微不注意可能导致数据丢失或者触发未知bug，64位事务id改造的问题pg走的很谨慎。不过社区还是在考虑这个问题，期待有一天在某个pg版本中事务id回卷问题彻底解决。&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务id参考
 &lt;div id="事务id参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1id%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;《Postgresql指南 内幕探索》
&lt;a href="https://www.interdb.jp/pg/pgsql05.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05.html&lt;/a&gt;
&lt;a href="https://www.interdb.jp/pg/pgsql06.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql06.html&lt;/a&gt;
&lt;a href="https://www.slideshare.net/masahikosawada98/introduction-vauum-freezing-xid-wraparound?from_action=save" target="_blank" rel="noreferrer"&gt;https://www.slideshare.net/masahikosawada98/introduction-vauum-freezing-xid-wraparound?from_action=save&lt;/a&gt;
&lt;a href="https://www.modb.pro/db/427012" target="_blank" rel="noreferrer"&gt;https://www.modb.pro/db/427012&lt;/a&gt;
&lt;a href="https://www.modb.pro/db/377530" target="_blank" rel="noreferrer"&gt;https://www.modb.pro/db/377530&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/13/routine-vacuuming.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/routine-vacuuming.html&lt;/a&gt;
&lt;a href="https://blog.csdn.net/weixin_30916255/article/details/112365965" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/weixin_30916255/article/details/112365965&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/FullTransactionId" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/FullTransactionId&lt;/a&gt;
&lt;a href="https://www.bookstack.cn/read/aliyun-rds-core/bd7e1c1955b35f7d.md" target="_blank" rel="noreferrer"&gt;https://www.bookstack.cn/read/aliyun-rds-core/bd7e1c1955b35f7d.md&lt;/a&gt;
&lt;a href="https://github.com/digoal/blog/blob/master/201605/20160520_01.md" target="_blank" rel="noreferrer"&gt;https://github.com/digoal/blog/blob/master/201605/20160520_01.md&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;&lt;strong&gt;事务相关的元组结构&lt;/strong&gt;
 &lt;div id="事务相关的元组结构" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%9b%b8%e5%85%b3%e7%9a%84%e5%85%83%e7%bb%84%e7%bb%93%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;元组结构中包含很多pg的mvcc所必要的信息，下面的内容将梳理xmin,xmax,t_ctid,cmin,cmax,combo cid,tuple id的含义和关系&lt;/p&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;物理结构&lt;/strong&gt;
 &lt;div id="物理结构" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%89%a9%e7%90%86%e7%bb%93%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2d7dd2db28e1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HeapTupleHeaderData&lt;/code&gt;相当于tuple的header，其结构在&lt;code&gt;src/include/access/htup_details.h&lt;/code&gt;中定义&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; HeapTupleFields
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId t_xmin;		&lt;span style="color:#75715e"&gt;/* 插入事务的ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId t_xmax;		&lt;span style="color:#75715e"&gt;/* 擅长或锁定事务的ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		CommandId	t_cid;		&lt;span style="color:#75715e"&gt;/* 插入或删除的命令ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		TransactionId t_xvac;	&lt;span style="color:#75715e"&gt;/* VACUUM FULL的事务ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}			t_field3;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} HeapTupleFields;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; DatumTupleFields
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} DatumTupleFields;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; HeapTupleHeaderData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		HeapTupleFields t_heap;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		DatumTupleFields t_datum;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}			t_choice;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ItemPointerData t_ctid;		&lt;span style="color:#75715e"&gt;/* 当前元组或更新元组的TID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;HeapTupleHeaderData&lt;/code&gt;中有5个定义对MVCC及其重要。其中x代表transaction，c代表command，t代表tuple，便于分类理解&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;t_xmin&lt;/code&gt;：表示插入该元组的事务ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t_xmax&lt;/code&gt;：表示删除该元组的事务ID或者回滚事务ID。如果没有被删除或更新元组，xmax是0；如果删除或更新元组后回滚，xmax是回滚事务ID。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t_xvac&lt;/code&gt;:元组被vacuum时设置的xid，此时元组已脱离了原来的事务&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t_cid&lt;/code&gt;：表示命令标识(command id,cid)，一个事务可以包含多个SQL，事务中的命令从0开始编号，cid依次递增。CommandId是uint32类型，最大支持2^32 - 1个命令，为了节省资源，而且查询不会影响行的事务顺序，查询不会增加cid（这点类似事务id分配）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t_ctid&lt;/code&gt;：保存指向自身或新元组标识符(tid）,tid是标识表中元组的，是元组的物理地址。如果一条记录被修改多次，那么该记录会存在多个版本。各个版本通过t_cid串联，形成一个版本链。通过这个版本链，可以找到最新的版本&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;系统列&lt;/strong&gt;
 &lt;div id="系统列" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%b3%bb%e7%bb%9f%e5%88%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;每个元组都有6个系统列（每个tuple都有，可以直接查到），它们是&lt;code&gt;tableoid&lt;/code&gt;,&lt;code&gt;xmin&lt;/code&gt;,&lt;code&gt;xmax&lt;/code&gt;,&lt;code&gt;cmin&lt;/code&gt;,&lt;code&gt;cmax&lt;/code&gt;,&lt;code&gt;ctid&lt;/code&gt; 。&lt;code&gt;tableoid&lt;/code&gt;是表的oid，在查询和dml时是不会变化的，这里重点讲其余5个系统列&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,cmax,ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;616&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;619&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cmin&lt;/code&gt;：插入元组的cid，command id&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmax&lt;/code&gt;：删除元组的cid，command id&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中&lt;code&gt;xmin&lt;/code&gt;,&lt;code&gt;xman&lt;/code&gt;,&lt;code&gt;xvac&lt;/code&gt;是物理存储的，定义在&lt;code&gt;struct HeapTupleFields&lt;/code&gt;中，但是&lt;code&gt;cmin&lt;/code&gt;和&lt;code&gt;cmax&lt;/code&gt;没有定义在HeapTupleFields结构体中的，结构体有关于command的&lt;code&gt;t_cid&lt;/code&gt;，&lt;code&gt;cmin&lt;/code&gt;、&lt;code&gt;cmax&lt;/code&gt;就是从&lt;code&gt;t_cid&lt;/code&gt;取数&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cmin&lt;/code&gt;，&lt;code&gt;cmax&lt;/code&gt;的源码还是在&lt;code&gt;src/include/access/htup_details.h&lt;/code&gt;中&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* SetCmin is reasonably simple since we never need a combo CID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HeapTupleHeaderSetCmin(tup, cid) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;do { \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	Assert(!((tup)-&amp;gt;t_infomask &amp;amp; HEAP_MOVED)); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	(tup)-&amp;gt;t_choice.t_heap.t_field3.t_cid = (cid); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	(tup)-&amp;gt;t_infomask &amp;amp;= ~HEAP_COMBOCID; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;} while (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* SetCmax must be used after HeapTupleHeaderAdjustCmax; see combocid.c */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HeapTupleHeaderSetCmax(tup, cid, iscombo) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;do { \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	Assert(!((tup)-&amp;gt;t_infomask &amp;amp; HEAP_MOVED)); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	(tup)-&amp;gt;t_choice.t_heap.t_field3.t_cid = (cid); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	if (iscombo) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		(tup)-&amp;gt;t_infomask |= HEAP_COMBOCID; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	else \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		(tup)-&amp;gt;t_infomask &amp;amp;= ~HEAP_COMBOCID; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;} while (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * HeapTupleHeaderGetRawCommandId will give you what&amp;#39;s in the header whether
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * it is useful or not. Most code should use HeapTupleHeaderGetCmin or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * HeapTupleHeaderGetCmax instead, but note that those Assert that you can
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * get a legitimate result, ie you are in the originating transaction!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HeapTupleHeaderGetRawCommandId(tup) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;( \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	(tup)-&amp;gt;t_choice.t_heap.t_field3.t_cid \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;combocid&lt;/strong&gt;
 &lt;div id="combocid" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#combocid" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在8.3以前&lt;code&gt;cmin&lt;/code&gt;和&lt;code&gt;cmax&lt;/code&gt;是分开的。后来考虑到同事务对一条数据既插入又删除的情况比较少，而且事务结束后&lt;code&gt;cmin&lt;/code&gt;、&lt;code&gt;cmax&lt;/code&gt;都不需要，同时为了节省header空间，&lt;code&gt;cmin&lt;/code&gt;、&lt;code&gt;cmax&lt;/code&gt;合并到一起称为combo command id即&lt;code&gt;combocid&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;combocid&lt;/code&gt;源码位置&lt;code&gt;src/backend/utils/time/combocid.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* Key and entry structures for the hash table */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;typedef struct
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CommandId	cmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CommandId	cmax;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; ComboCidKeyData;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* comboid的结构为cmin和cmax*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; CommandId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GetComboCommandId(CommandId cmin, CommandId cmax)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 当第一次使用到combo cid时才会生成hash表 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (comboHash &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HASHCTL		hash_ctl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 生成数组、hash表 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	comboCids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (ComboCidKeyData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		MemoryContextAlloc(TopTransactionContext,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 sizeof(ComboCidKeyData) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; CCID_ARRAY_SIZE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sizeComboCids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CCID_ARRAY_SIZE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	usedComboCids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	memset(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;hash_ctl, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, sizeof(hash_ctl));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	comboHash &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hash_create(&lt;span style="color:#e6db74"&gt;&amp;#34;Combo CIDs&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							CCID_HASH_SIZE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;hash_ctl,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							HASH_ELEM &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH_BLOBS &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH_CONTEXT);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;combocid&lt;/code&gt;存放在hash表中。当事务第一次使用&lt;code&gt;combocid&lt;/code&gt;时，会在内存中开辟一小块地方存放&lt;code&gt;combocid&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以这几个command id的关系和调用过程：&lt;strong&gt;combocid-&amp;gt;(cmin,cmax)-&amp;gt;(t_ctid,t_ctid)&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;简单的事务相关id和系统列关系
 &lt;div id="简单的事务相关id和系统列关系" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%ae%80%e5%8d%95%e7%9a%84%e4%ba%8b%e5%8a%a1%e7%9b%b8%e5%85%b3id%e5%92%8c%e7%b3%bb%e7%bb%9f%e5%88%97%e5%85%b3%e7%b3%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;看了这么多id和源码，似乎有点乱。为了便于理解和记忆，梳理一下这些事务id、command id、tuple id的关系&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/077888610817.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;事务的初步体验
 &lt;div id="事务的初步体验" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%88%9d%e6%ad%a5%e4%bd%93%e9%aa%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在没有工具和插件的条件下，初步体验一下这几个系统列在事务中的变化&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,cmax,ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;622&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--更新后，xmin+1,ctid+1，这里其实出现了新的tuple
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,cmax,ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;623&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--xmax会记录回滚事务id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--xmin，ctid又回到了旧值，其实旧tuple不怎么变化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,cmax,ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;622&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;623&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--再次更新，tuple号跳过了2，直接到3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,cmax,ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+------+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;624&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;元组header与事务
 &lt;div id="元组header与事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%83%e7%bb%84header%e4%b8%8e%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;pageinspect插件
 &lt;div id="pageinspect插件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pageinspect%e6%8f%92%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;直接看行的变化是看不到旧的tuple的，所以需要pageinsect插件。pageinsect插件是pg自带的第三方插件，可以展示数据页面的具体内容。为了观察tuple是如何支持事务的，需要用到&lt;code&gt;get_raw_page()&lt;/code&gt;和&lt;code&gt;heap_page_items()&lt;/code&gt;两个函数。
&lt;code&gt;get_raw_page()&lt;/code&gt;：返回指定块的二进制值。其中fork有main、fsm、vm、init几个值。main是数据文件主文件，fsm是free space map块文件，vm是可见性映射快文件，init是初始化的块，如果不指定fork默认为main
&lt;code&gt;heap_page_items()&lt;/code&gt;：显示一个堆页面上的所有行指针，即使因为mvcc看不到的行也会被展示。
一般把&lt;code&gt;get_raw_page()&lt;/code&gt;当做参数传入&lt;code&gt;heap_page_items()&lt;/code&gt;以展示元组的header、pointer信息和数据本身
&lt;code&gt;heap_tuple_infomask_flags&lt;/code&gt;：将十进制的infomask，infomask2值转换成其含义（标识），输出2列：所有单标识和联合标识。(infomask后面会介绍)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; extension pageinspect;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; EXTENSION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; t_xmin,t_xmax,t_field3 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; t_cid,t_ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+--------+-------+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;633&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;lp（line pointer）
 &lt;div id="lpline-pointer" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lpline-pointer" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;line pointer直译是行指针的意思，实际上是页面中的行指针&lt;strong&gt;编号&lt;/strong&gt;，相当于在页面中标记了一个元组。t_ctid看上去更像是tuple id，但是ctid只是（表的page号，行指针编号）的组合，ctid可以指向下个lp 。
例如对一个元组做一次update，会增加一个元组，新元组的lp编号+1，旧tuple的ctid指向新tuple的lp，新tuple的ctid指向自己&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lp,t_ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lp,t_ctid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_ctid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;lp源码在&lt;code&gt;src/include/storage/itemid.h&lt;/code&gt;中，&lt;code&gt;ItemIdData&lt;/code&gt;结构保存了元组的offset位置，状态，长度&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; ItemIdData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt;	lp_off:&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;,		&lt;span style="color:#75715e"&gt;/* 元组在页面的偏移量 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				lp_flags:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,		&lt;span style="color:#75715e"&gt;/* lp的状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				lp_len:&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;;		&lt;span style="color:#75715e"&gt;/* 元组的长度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} ItemIdData;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; ItemIdData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ItemId;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* lp_off:15代表位域，lp_off占用unsigned中的15位，3个定义加起来总共32位。所以ItemIdData是int类型，4个字节，共32位 */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;lp_flags&lt;/code&gt;定义了4种状态&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *lp_flags has these possible states. An UNUSED line pointer is available
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *for immediate re-use, the other states are not.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define LP_UNUSED		0		&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* lp没有被使用，元组长度pl_len总是为0 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define LP_NORMAL		1		&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* lp正在使用，元组长度pl_len总是&amp;gt;0 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define LP_REDIRECT		2		&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* HOT redirect重定向到其他lp (should have lp_len=0) */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define LP_DEAD			3		&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* dead的lp，可被vacuum */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lp,lp_flags,lp_off,lp_len &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_off &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_len 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----+----------+--------+--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8160&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;infomask
 &lt;div id="infomask" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#infomask" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;infomask提供了事务、锁、元组状态等信息，比如提交、终止、锁、HOT信息等等。header中有两个infomask：&lt;code&gt;infomask&lt;/code&gt;和&lt;code&gt;infomask2&lt;/code&gt;。他们存储的信息有所不同&lt;/p&gt;

&lt;h4 class="relative group"&gt;infomask,infomask2
 &lt;div id="infomaskinfomask2" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#infomaskinfomask2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;infomask&lt;/code&gt;源码还是在&lt;code&gt;src/include/access/htup_details.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint16		t_infomask2;	&lt;span style="color:#75715e"&gt;/* number of attributes + various flags */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint16		t_infomask;		&lt;span style="color:#75715e"&gt;/* various flag bits, see below */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;infomask的标识含义
 &lt;div id="infomask的标识含义" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#infomask%e7%9a%84%e6%a0%87%e8%af%86%e5%90%ab%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * information stored in t_infomask:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_HASNULL			0x0001	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组中是否有null值 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_HASVARWIDTH		0x0002	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组是否是变长的，如varchar类型 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_HASEXTERNAL		0x0004	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 是否有toast存储 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_HASOID_OLD			0x0008	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组是否有OID */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_KEYSHR_LOCK	0x0010	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组是否有for key-share锁 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_COMBOCID			0x0020	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_cid是否是comboCID */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_EXCL_LOCK		0x0040	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组是否有for update锁 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_LOCK_ONLY		0x0080	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* xmax只起锁作用 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* xmax is a shared locker */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_SHR_LOCK	(HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_LOCK_MASK	(HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;						 HEAP_XMAX_KEYSHR_LOCK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMIN_COMMITTED		0x0100	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmin对应的插入元组的事务已提交 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMIN_INVALID		0x0200	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmin对于的插入元组的事务无效或终止 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMIN_FROZEN		(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_COMMITTED		0x0400	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax对于的删除元组的事务是否提交 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_INVALID		0x0800	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax对于的删除元组的事务无效或终止 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_IS_MULTI		0x1000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax是否使用MultiXactId */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_UPDATED			0x2000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 该元组是数据行被更新后的版本 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_MOVED_OFF			0x4000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 被 9.0 之前的 VACUUM FULL 移动到另外的地方，为了兼容二进制程序升级而保留 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_MOVED_IN			0x8000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 与 HEAP_MOVED_OFF 相对，表明是从别处移动过来的，也是为了兼容性而保留 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XACT_MASK			0xFFF0	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 可见性相关位 */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;infomask2的标识含义
 &lt;div id="infomask2的标识含义" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#infomask2%e7%9a%84%e6%a0%87%e8%af%86%e5%90%ab%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_NATTS_MASK			0x07FF	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 有11位用来保存元组的列的数量，（MaxHeapAttributeNumber用户的列长度是1600个）*/&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* bits 0x1800 are available */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_KEYS_UPDATED		0x2000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组更新或者删除 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_HOT_UPDATED		0x4000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 元组更新后，新元组是HOT */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_ONLY_TUPLE			0x8000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* HOT tuple */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP2_XACT_MASK			0xE000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* 可见性相关位 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_TUPLE_HAS_MATCH	HEAP_ONLY_TUPLE 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*在 Hash Join 中临时使用的标志，只用于 Hash 表中的 tuple，且不需要可见性信息，所以我们可以用一个可见性标志覆盖他，而不是使用一个单独的位 */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;infomask的位与位计算
 &lt;div id="infomask的位与位计算" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#infomask%e7%9a%84%e4%bd%8d%e4%b8%8e%e4%bd%8d%e8%ae%a1%e7%ae%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;把16进制转换为2进制，就比较容易理解&lt;strong&gt;位&lt;/strong&gt;所代表的含义&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--将16进制的1600转换为2进制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; x&lt;span style="color:#e6db74"&gt;&amp;#39;1600&amp;#39;&lt;/span&gt;::bit(&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bit 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0001011000000000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;infomask：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000000001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0001&lt;/span&gt; HEAP_HASNULL			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000000010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0002&lt;/span&gt; HEAP_HASVARWIDTH		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000000100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0004&lt;/span&gt; HEAP_HASEXTERNAL		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000001000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0008&lt;/span&gt; HEAP_HASOID_OLD			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0010&lt;/span&gt; HEAP_XMAX_KEYSHR_LOCK	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000000100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0020&lt;/span&gt; HEAP_COMBOCID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000001000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0040&lt;/span&gt; HEAP_XMAX_EXCL_LOCK
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000010000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0080&lt;/span&gt; HEAP_XMAX_LOCK_ONLY		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000001010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0050&lt;/span&gt; HEAP_XMAX_SHR_LOCK &lt;span style="color:#960050;background-color:#1e0010"&gt;位或计算一下&lt;/span&gt;(HEAP_XMAX_EXCL_LOCK &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HEAP_XMAX_KEYSHR_LOCK)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000001010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0050&lt;/span&gt; HEAP_LOCK_MASK &lt;span style="color:#960050;background-color:#1e0010"&gt;位或计算一下&lt;/span&gt;(HEAP_XMAX_SHR_LOCK &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HEAP_XMAX_EXCL_LOCK &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HEAP_XMAX_KEYSHR_LOCK)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000000100000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0100&lt;/span&gt; HEAP_XMIN_COMMITTED		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000001000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0200&lt;/span&gt; HEAP_XMIN_INVALID		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000001100000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0300&lt;/span&gt; HEAP_XMIN_FROZEN &lt;span style="color:#960050;background-color:#1e0010"&gt;位或计算一下&lt;/span&gt;(HEAP_XMIN_COMMITTED&lt;span style="color:#f92672"&gt;|&lt;/span&gt;HEAP_XMIN_INVALID)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000010000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0400&lt;/span&gt; HEAP_XMAX_COMMITTED		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000100000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0800&lt;/span&gt; HEAP_XMAX_INVALID		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0001000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x1000&lt;/span&gt; HEAP_XMAX_IS_MULTI		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0010000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x2000&lt;/span&gt; HEAP_UPDATED			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0100000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x4000&lt;/span&gt; HEAP_MOVED_OFF			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1000000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x8000&lt;/span&gt; HEAP_MOVED_IN			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1100000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xC000&lt;/span&gt; HEAP_MOVED &lt;span style="color:#960050;background-color:#1e0010"&gt;位或计算一下&lt;/span&gt;(HEAP_MOVED_OFF &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HEAP_MOVED_IN)&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4000&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8000&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1111111111110000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xFFF0&lt;/span&gt; HEAP_XACT_MASK&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;infomask2:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0000011111111111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x07FF&lt;/span&gt; HEAP_NATTS_MASK pg库的列最多有1600个&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0000011001000000&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，所以前&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;位保存元组列足够&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0001100000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x1800&lt;/span&gt; available位&lt;span style="color:#960050;background-color:#1e0010"&gt;，看上去是空闲不用的&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0010000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x2000&lt;/span&gt; HEAP_KEYS_UPDATED 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0100000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x4000&lt;/span&gt; HEAP_HOT_UPDATED 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1000000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x8000&lt;/span&gt; HEAP_ONLY_TUPLE 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1110000000000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xE000&lt;/span&gt; HEAP2_XACT_MASK&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;怎么计算infomask？
 &lt;div id="怎么计算infomask" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%80%8e%e4%b9%88%e8%ae%a1%e7%ae%97infomask" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;infomask的标识是16进制，pageinspect插件查infomask出来的是10进制。需要to_hex()，10进制转换为16进制的函数 ，做一个转换&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lp,t_ctid,to_hex(t_infomask) infomask,to_hex(t_infomask2) infomask2 &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; infomask &lt;span style="color:#f92672"&gt;|&lt;/span&gt; infomask2 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----+--------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;b00 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;infomask=2b00，还是有点转不过来，转成16进制有点难凑，转成二进制对着上面的位含义再凑一下&lt;code&gt;0010101100000000=HEAP_UPDATED+HEAP_XMAX_INVALID+HEAP_XMIN_FROZEN&lt;/code&gt;&lt;br&gt;
其含义为：标识元组更新过，xmax为invalid也就是0，xmin frozen对所有事务可见
infomask2=1，二进制的前11位，十进制的前2047（最多1600列），都是代表用户列的个数，所以1代表只有1个列&lt;/p&gt;
&lt;p&gt;手动算infomask有点麻烦，从pg13开始pageinspect提供了函数&lt;code&gt;heap_tuple_infomask_flags&lt;/code&gt;转换infomask,infomask2的含义。有单独位标识的是raw flag,联合多个位标识的是combined_flags&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; t_ctid, raw_flags, combined_flags
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; t_infomask &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; t_infomask2 &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+------------------------------------------------------------------------+--------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID,HEAP_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_FROZEN&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;提交日志clog
 &lt;div id="提交日志clog" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%8f%90%e4%ba%a4%e6%97%a5%e5%bf%97clog" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg用提交日志（commit log，clog）来保存事务状态。pg会在事务完成前就将事务写进wal日志，这也是wal的含义。如果终止事务，将事务状态写进wal和clog，在实例恢复时，也能知道事务是没有完成提交的。
在需要获取事务状态时，比如判断事务可见性时，pg会读取clog的事务状态。
&lt;strong&gt;事务状态&lt;/strong&gt;
源码&lt;code&gt;src/include/access/clog.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_IN_PROGRESS		0x00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_COMMITTED		0x01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_ABORTED			0x02
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TRANSACTION_STATUS_SUB_COMMITTED	 0x03&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;clog中事务定义了4种状态：&lt;code&gt;IN_PROGRESS&lt;/code&gt;,&lt;code&gt;COMMITTED&lt;/code&gt;,&lt;code&gt;ABORTD&lt;/code&gt;,&lt;code&gt;SUB_COMMITTED&lt;/code&gt;
&lt;strong&gt;事务状态大小&lt;/strong&gt;
源码&lt;code&gt;src/backend/access/transam/clog.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* We need two bits per xact, so four xacts fit in a byte */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_BITS_PER_XACT	2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACTS_PER_BYTE 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define CLOG_XACT_BITMASK	((1 &amp;lt;&amp;lt; CLOG_BITS_PER_XACT) - 1)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;事务状态非常小，一个事务只需要2位，1字节可以保存4个事务状态
一个标准的page可以保留 8K*4=32768个事务状态
&lt;strong&gt;clog持久化&lt;/strong&gt;
pg关库或落盘时，clog数据会写入pg_clog目录下，在10.0及以后的版本，pg_clog重命名为pg_xact。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl pg_xact&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; Mar &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 23:33 &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;磁盘上的clog文件命名为0000，0001等。
clog文件大小为256KB，而内存中通过page存储事务为8K，所以0000文件的大小只会是8192的倍数，当写了32个clog page后，下个page便写入0001文件。PostgreSQL 启动时会从 pg_xact 中读取事务的状态加载至内存。
系统运行过程中，并不是所有事务的状态都需要长期保留在 CLOG 文件中，因此 vacuum 操作会定期将不再使用的 CLOG 文件删除&lt;/p&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;Hint Bits&lt;/strong&gt;
 &lt;div id="hint-bits" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hint-bits" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;什么是hintbits？
 &lt;div id="什么是hintbits" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afhintbits" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;hint bits是为了标记那些创建或删除的行的事务是否提交或终止。如果没有hint bits，事务可见性需要访问磁盘pg_clog或pg_subtrans，这种访问代价比较昂贵。如果元组被设置了hint bits，那么访问page中的元组，就能知道元组状态，不需要额外的访问。
源码中使用&lt;code&gt;SetHintBits()&lt;/code&gt;函数设置hintbits
如&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_COMMITTED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			InvalidTransactionId);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SetHintBits&lt;/code&gt;设置的只是infomask中的2位，共4种hint bits（其实这2位infomask还有一个联合标识HEAP_XMIN_FROZEN，能看出来hintbits就是单纯为了标记事务状态的）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMIN_COMMITTED	0x0100	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmin对应的插入或更新事务已提交 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMIN_INVALID		0x0200	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmin对于的插入或更新事务无效或终止 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_COMMITTED		0x0400	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax对于的删除或更新事务是否提交 */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_INVALID		0x0800	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax对于的删除或更新事务无效或终止 */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;查询会产生写入
 &lt;div id="查询会产生写入" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9f%a5%e8%af%a2%e4%bc%9a%e4%ba%a7%e7%94%9f%e5%86%99%e5%85%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;事务开始后，pg的dml事务会在元组header中记录t_min等事务id和事务状态。但事务结束时，不会在header中作任何事情，而是在后面的DML或者DQL，VACUUM等SQL扫描到对应的TUPLE时，触发&lt;code&gt;SetHintBits&lt;/code&gt;的操作（产生新快照访问数据时&lt;code&gt;SetHintBits&lt;/code&gt;，代码在&lt;code&gt;HeapTupleSatisfiesMVCC()&lt;/code&gt;中，后面可见性规则小节会介绍）。&lt;/p&gt;
&lt;p&gt;在没有触发&lt;code&gt;SetHintBits&lt;/code&gt;之前，pg在clog中寻找事务状态；触发SetHintBits后，在数据页的元组header中找hintbits所代表的事务状态。
例如一个insert语句&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; t_ctid, raw_flags, combined_flags
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;-#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;-#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;-#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; t_infomask &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; t_infomask2 &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+---------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1; &lt;span style="color:#75715e"&gt;--仅做一次查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; t_ctid, raw_flags, combined_flags
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; t_infomask &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; t_infomask2 &lt;span style="color:#66d9ef"&gt;IS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+-----------------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一次查询后，t_infomask发生了变化，说明tuple header发生了变化。
在insert后，SetHintBits只有HEAP_XMAX_INVALID，因为insert本身只会更新xmin，无论事物是否提交或终止（退出或rollback）xmax都是没用的，可以随事务一起SetHintBits为HEAP_XMAX_INVALID
但是事务可能提交，也可能终止（退出或rollback），又由于事务完成不会更新元组，所以HEAP_XMIN_COMMITTED不能随事务完成而SetHintBits
在检测事务可见性（heapam_visibility.c）时，可见性检测更新了元组的事务状态SetHintBits到t_infomask中，所以查询更新了HEAP_XMIN_COMMITTED&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;hintbits优点&lt;/strong&gt;：事务中数据更新的完成（包括失败），不会对元组产生任何写入。提交和回退会非常快。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;hintbits缺点&lt;/strong&gt;：如果一个事务更新了多行，下一次查询检测可见性时可能会从pg_clog中读取事务状态，并更新非常多的page。&lt;/p&gt;

&lt;h4 class="relative group"&gt;hintbits是否会产生WAL日志？
 &lt;div id="hintbits是否会产生wal日志" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hintbits%e6%98%af%e5%90%a6%e4%bc%9a%e4%ba%a7%e7%94%9fwal%e6%97%a5%e5%bf%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;在开启 checksum 或者参数 wal_log_hints 为 true 的情况下，如果 checkpoint 后第一次使页面 dirty 的操作是更新 Hint Bits，则会产生一条 WAL 日志，将当前页面写入 WAL 日志中(即 Full Page Image)，避免产生部分写，导致数据 checksum 异常。
因此，在开启 checksum 或者 参数 wal_log_hints 为 true 时，即便执行 SELECT，也可能更改页面的 Hint Bits，从而导致产生 WAL 日志，这会在一定程度上增加 WAL 日志占用的存储空间。如果在使用pg中发现执行SELECT会触发磁盘的写入操作，可以检查一下是否开启了CHECKSUM或者wal_log_hints。&lt;/p&gt;

&lt;h4 class="relative group"&gt;hintbits为什么延迟更新？
 &lt;div id="hintbits为什么延迟更新" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hintbits%e4%b8%ba%e4%bb%80%e4%b9%88%e5%bb%b6%e8%bf%9f%e6%9b%b4%e6%96%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;源码&lt;code&gt;src/backend/access/heap/heapam_visibility.c&lt;/code&gt;里，在可见性规则&lt;code&gt;HeapTupleSatisfiesMVCC()&lt;/code&gt;注释中有一段hintbits为什么延迟更新的解释&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*插入、删除操作还在跑时，哪怕事务已提交或者回退，都不会更新元组上的hint bits，也就是更新事务状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*因为在高并发场景下共享数据结构可能会造成争用，而且这也不会影响可见性判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*hintbits只会发生在首次全新快照访问已完成事务的数据之后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*所以HeapTupleSatisfiesMVCC每次都会运行TransactionIdIsCurrentTransactionId，XidInMVCCSnapshot，以判断是否当前事务的元组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*在老版本中，pg尝试立即更新hintbits（即使事务在运行中），但是造成对PGXACT array的更多争用 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;简单点说，hintbits立即更新性能非常差，所以将事务状态先放在clog，减少PGXACT的争用，以提升性能。hintbits延迟更新就造成了后续查询可能会更新元组的情况&lt;/p&gt;

&lt;h2 class="relative group"&gt;元组的增删改
 &lt;div id="元组的增删改" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%83%e7%bb%84%e7%9a%84%e5%a2%9e%e5%88%a0%e6%94%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在积累了元组header、系统列、clog、hintbits等知识点后，我们来看下pg是如何完成增删改操作。&lt;/p&gt;

&lt;h3 class="relative group"&gt;观察DML事务
 &lt;div id="观察dml事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%a7%82%e5%af%9fdml%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;通过对lp,lp_flags,ctid,xmin,xmax,cid(cmin,cmax),infomask,infomask2这些元组头部信息，观察pg的DML事务行为
观察这些内容会使用以下sql&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; t_ctid,lp,&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; lp_flags &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0:LP_UNUSED&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_NORMAL&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_REDIRECT&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_DEAD&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; lp_flags,t_xmin,t_xmax,t_field3 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; t_cid, raw_flags, info.combined_flags &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)) item,&lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2) info &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; lp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(稍微说下，有些资料里喜欢这样&lt;code&gt;SELECT '(0,'||lp||')' AS ctid&lt;/code&gt;,这样写不太合适，lp跟ctid是两码事，lp相当于行号，ctid是指向行号的，lp是可以不等于ctid的）
为了更好的阅读，创建一个view简化一下sql&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;view&lt;/span&gt; vlzl1 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; t_ctid,lp,&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; lp_flags &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0:LP_UNUSED&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_NORMAL&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_REDIRECT&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LP_DEAD&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; lp_flags,t_xmin,t_xmax,t_field3 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; t_cid, raw_flags, info.combined_flags &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)) item,&lt;span style="color:#66d9ef"&gt;LATERAL&lt;/span&gt; heap_tuple_infomask_flags(t_infomask, t_infomask2) info &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; lp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;查询就像这样&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;x
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Expanded display &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;[ RECORD &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; ]&lt;span style="color:#75715e"&gt;--+-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;653&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;combined_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;插入
 &lt;div id="插入" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%8f%92%e5%85%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;清空数据，insert插入一行&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+---------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ctid指向(page 0,lp 1)，也就指向自身
lp，line pointer行指针编号，递增
2个元组xmin是同一个事务，表示2个元组是一个事务插入
xmax为0表示无效事务ID，infomask也仅说明xmax无效，该元组还没有&amp;quot;经历&amp;quot;删除事务
cid从0开始递增，0代表事务第一个command，1代表事务第二个command&lt;/p&gt;

&lt;h3 class="relative group"&gt;删除
 &lt;div id="删除" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%88%a0%e9%99%a4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DELETE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+-----------------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;665&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_KEYS_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;删除了第一个元组，元组没有物理上删除，只是几个属性打了标记
ctid未变还是指向自身
xmax更新为删除事务id
infomask标识有HEAP_KEYS_UPDATED表示元组删除了（实际上HEAP_KEYS_UPDATED的有删除或更新的意思）
虽然只更新了第一个元组，但是第二个元组更新了infomask HEAP_XMIN_COMMITTED&lt;/p&gt;

&lt;h3 class="relative group"&gt;更新
 &lt;div id="更新" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9b%b4%e6%96%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+-------------------------------------------------------------+----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;665&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_KEYS_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;666&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_HOT_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;666&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;更新事务不会再元组上操作，而是将老元组标识为不可用，新增一个新元组
lp=2 为更新事务的老元组，t_xmax更新为更新事务id，infomask增加标识HEAP_HOT_UPDATED，表示该元组是hot，ctid指向了新元组
lp=3 为更新事务的新元组，相当于插入了一个新元组，不过xmin事务id跟老元组xmax一致，并且infomask有额外标识HEAP_UPDATED表示该元组是update后的row
另外，一个看不见的被删除的元组 lp=1，在不相关的更新事务发生后，infomask增加了标识HEAP_XMAX_COMMITTED&lt;/p&gt;

&lt;h3 class="relative group"&gt;回退
 &lt;div id="回退" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%9b%9e%e9%80%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;TRUNCATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--插入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+---------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;679&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--插入回退
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+---------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;679&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--插入后回退，元组header信息没有任何变化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1 ; &lt;span style="color:#75715e"&gt;--删除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DELETE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+-----------------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;684&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;685&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;686&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_KEYS_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--删除回退
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+-----------------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;684&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;685&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;686&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_KEYS_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--删除后回退，元组header信息没有任何变化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; ; &lt;span style="color:#75715e"&gt;--更新
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+--------------------------------------------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;684&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;685&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;688&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_HOT_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;688&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--更新回退
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+--------------------------------------------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;684&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;685&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;688&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMIN_COMMITTED,HEAP_HOT_UPDATED&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;688&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_XMAX_INVALID,HEAP_UPDATED,HEAP_ONLY_TUPLE&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--更新后回退，元组header信息没有任何变化&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;• 事务回退，元组信息不会有任何变化。这也是为什么pg的mvcc不用担心回滚段不够用，因为回滚只是可见性操作，不会更新数据本身
• xmax在回退后也没有变，说明xmax有值不一定代表元组被删除，也可能是删除或更新事务回退了
• 但是，只要产生了可见性检测，哪怕不产生数据变化，所有元组的infomask都会更新HEAP_XMIN_INVALID。其中非HOT元组都加上HEAP_XMIN_INVALID，HOT指向的元组当然也是HEAP_XMIN_INVALID&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参考&lt;/strong&gt;
books：
《postgresql指南 内幕探索》
《postgresql实战》
《postgresql技术内幕 事务处理深度探索》
《postgresql数据库内核分析》
&lt;a href="https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf" target="_blank" rel="noreferrer"&gt;https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf&lt;/a&gt;
官方资料：
&lt;a href="https://en.wikipedia.org/wiki/Concurrency_control" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Concurrency_control&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/Hint_Bits" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Hint_Bits&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/10/storage-page-layout.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/10/storage-page-layout.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/13/pageinspect.html3" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/pageinspect.html3&lt;/a&gt;
pg事务必读文章 interdb
&lt;a href="https://www.interdb.jp/pg/pgsql05.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05.html&lt;/a&gt;
&lt;a href="https://www.interdb.jp/pg/pgsql06.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql06.html&lt;/a&gt;
源码大佬
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/102920988" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/102920988&lt;/a&gt;
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/127955762" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/127955762&lt;/a&gt;
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/125023923" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/125023923&lt;/a&gt;
pg的快照优化性能对比
&lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462" target="_blank" rel="noreferrer"&gt;https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462&lt;/a&gt;
其他资料
&lt;a href="https://brandur.org/postgres-atomicity" target="_blank" rel="noreferrer"&gt;https://brandur.org/postgres-atomicity&lt;/a&gt;
&lt;a href="https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;pg中的快照
 &lt;div id="pg中的快照" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg%e4%b8%ad%e7%9a%84%e5%bf%ab%e7%85%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;快照（snapshot）是记录数据库当前瞬时状态的一个数据结构。pg数据库的快照保存当前所有活动事务的最小事务ID、最大事务ID、当前活跃事务列表、当前事务的command id等
快照数据保存在SnapshotData结构体类型中，源码&lt;code&gt;src/include/utils/snapshot.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; SnapshotData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SnapshotType snapshot_type; &lt;span style="color:#75715e"&gt;/* 快照类型 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransactionId xmin;			&lt;span style="color:#75715e"&gt;/* 事务ID小于xmin，对于快照可见 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransactionId xmax;			&lt;span style="color:#75715e"&gt;/* 事务ID大于xmax，对于快照不可见 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 获取快照时活跃事务列表。该列表仅包括xmin与xmax之间的txid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;xip;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uint32		xcnt;			&lt;span style="color:#75715e"&gt;/* xip_list保存在xip[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 获取快照时活跃子事务列表 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;subxip;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;int32		subxcnt;		&lt;span style="color:#75715e"&gt;/* 子事务保存在subxip[] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		suboverflowed;	&lt;span style="color:#75715e"&gt;/* 子事务是否溢出，子事务较多时会产生溢出 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		takenDuringRecovery;	&lt;span style="color:#75715e"&gt;/* 是否是恢复快照recovery-shaped snapshot? */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		copied;			&lt;span style="color:#75715e"&gt;/* 这里应该是快照是否是copy的（可重复读和串行化隔离级别，会copy快照）false if it&amp;#39;s a static snapshot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CommandId	curcid;			&lt;span style="color:#75715e"&gt;/* 事务中的command id，CID&amp;lt; curcid的可见 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TimestampTz whenTaken;		&lt;span style="color:#75715e"&gt;/* 生成快照的时间戳 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogRecPtr	lsn;			&lt;span style="color:#75715e"&gt;/* 生成快照的LSN */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} SnapshotData;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; SnapshotData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;Snapshot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;快照中最重要的信息是&lt;code&gt;xmin&lt;/code&gt;、&lt;code&gt;xmax&lt;/code&gt;、&lt;code&gt;xip_list&lt;/code&gt;。通过&lt;code&gt;pg_current_snapshot()&lt;/code&gt;（pg12及以前用 txid_current_snapshot () ）显示当前事务的快照。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意区分快照xmin、xmax跟元组上的xmin、xmax，含义是不一样的。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_current_snapshot();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_current_snapshot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;104&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;102&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;xmin&lt;/th&gt;
 &lt;th&gt;最早活跃的txid，所有比他更早的事务txid&amp;lt;xmin，要么提交和可见，要么回滚并成为死元组&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;xmax&lt;/td&gt;
 &lt;td&gt;第一个尚未分配的txid，xmax=latestCompletedXid+1，所有txid&amp;gt;=xmax的事务都未启动并对当前快照不可见&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;xip_list&lt;/td&gt;
 &lt;td&gt;xip_list存储在数组xip[]中。因为所有事务开始顺序性和完成顺序不一定是一致的，晚开始的事务可能早完成，所以只有xmin和xmax不能完全表达获取快照时的所有活动事务。xip_list保存获得快照时的活动事务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b7605604abbc.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;快照类型
 &lt;div id="快照类型" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bf%ab%e7%85%a7%e7%b1%bb%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;除了mvcc快照以外，pg在&lt;code&gt;src/include/utils/snapshot.h&lt;/code&gt;中还定义了一些其他的快照类型&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; SnapshotType
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 当且仅当元组符合mvcc快照可见规则时，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 最重要的一种快照事务，是pg用来实现mvcc的快照类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 元组可见性基于事务快照的xmin,xmax,xip_list,curcid等信息进行判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 如果命令发生了数据变更，当前mvcc快照是看不到的，需要再生成mvcc快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_MVCC &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 元组上的事务已提交，则可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 进行中的事务不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 命令发生了数据变更，当前self快照可以看见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_SELF,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 任何元组都可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_ANY,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * toast重要是有效的就可见。toast可见性依赖主表的元组可见性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_TOAST,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 命令发生了数据变更，当前dirty快照可以看见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * dirty快照会保存当前进行中元组的版本信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 快照xmin会设置成其他进行中事务的元组xmin，xmax类似
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_DIRTY,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* HISTORIC_MVCC快照规则与MVCC快照一致，用于逻辑解码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_HISTORIC_MVCC,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	判断死元组是否对一些事务可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SNAPSHOT_NON_VACUUMABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} SnapshotType;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;快照与隔离级别
 &lt;div id="快照与隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bf%ab%e7%85%a7%e4%b8%8e%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;不同的隔离级别，快照获取方式是不一样的&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ab95b43529f1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;rc模式需要事务中的每个sql都获得快照，而rr模式在事务中只使用一个快照。获得快照的方法在&lt;code&gt;GetTransactionSnapshot()&lt;/code&gt;函数中。&lt;/p&gt;

&lt;h3 class="relative group"&gt;进程上的事务结构体
 &lt;div id="进程上的事务结构体" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%9b%e7%a8%8b%e4%b8%8a%e7%9a%84%e4%ba%8b%e5%8a%a1%e7%bb%93%e6%9e%84%e4%bd%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg在获得快照数据的时候，需要检索所有backend进程的事务状态。&lt;/p&gt;
&lt;p&gt;所以在理解获得快照数据函数&lt;code&gt;GetSnapshotData()&lt;/code&gt;之前，需要先理解几个在关于backend process的结构体。这些结构体包括PGPROC、PGXACT、PROC_HDR(PROCGLOBAL)、ProcArray&lt;/p&gt;
&lt;p&gt;这些process相关结构体包含一些进程、锁等信息，这里只研究process里事务相关的信息。源码以pg13源码为示例&lt;/p&gt;

&lt;h4 class="relative group"&gt;PGPROC结构体
 &lt;div id="pgproc结构体" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pgproc%e7%bb%93%e6%9e%84%e4%bd%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;源码&lt;code&gt;src/include/storage/proc.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//每个backend进程在内存中都存储PGPROC结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//可以理解为backend进程的主结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; PGPROC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LocalTransactionId lxid;	&lt;span style="color:#75715e"&gt;/* local id of top-level transaction currently
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;								 * being executed by this proc, if running;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;								 * else InvalidLocalTransactionId */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; XidCache subxids;	&lt;span style="color:#75715e"&gt;/* 缓存子事务XIDs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* clog组事务状态更新 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		clogGroupMember;	&lt;span style="color:#75715e"&gt;/* 当前proc是否使用clog组提交 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_atomic_uint32 clogGroupNext; &lt;span style="color:#75715e"&gt;/* 原子int，指向下一个组成员proc */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransactionId clogGroupMemberXid;	&lt;span style="color:#75715e"&gt;/* 当前要提交的xid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XidStatus	clogGroupMemberXidStatus;	&lt;span style="color:#75715e"&gt;/* 当前要提交xid的状态 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			clogGroupMemberPage;	&lt;span style="color:#75715e"&gt;/* 当前要提交xid属于哪个page*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;XLogRecPtr	clogGroupMemberLsn; &lt;span style="color:#75715e"&gt;/* 当前要提交的xid的commit日志的lsn号 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* NOTE: &amp;#34;typedef struct PGPROC PGPROC&amp;#34; appears in storage/lock.h. 居然不跟结构体写在一起*/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;PGXACT结构体
 &lt;div id="pgxact结构体" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pgxact%e7%bb%93%e6%9e%84%e4%bd%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//在9.2以前，PGXACT的信息在PGPROC中，由于压测显示在多cpu系统中，因为减少了获取的缓存行数，把两者分开GetSnapshotData会更快，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; PGXACT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId xid;			&lt;span style="color:#75715e"&gt;/* id of top-level transaction currently being
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;								 * executed by this proc, if running and XID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;								 * is assigned; else InvalidTransactionId */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#75715e"&gt;// 看上是当前进程的xmax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId xmin;			&lt;span style="color:#75715e"&gt;/* 不包括lazy vaccum，事务开始时最小xid，vacuum无法删除xid &amp;gt;= xmin的元组*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint8		vacuumFlags;	&lt;span style="color:#75715e"&gt;/* vacuum-related flags, see above */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		overflowed; &lt;span style="color:#75715e"&gt;//PGXACT是否溢出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	uint8		nxids;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} PGXACT;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;能看出pgxact保存的信息比较简单，是backend的xmin、xmax等事务相关信息。&lt;strong&gt;而pgproc更倾向于保存backend的基本信息，pgproc中还是有一部分不太频繁调用的事务信息，不过最核心的进程事务信息在pgxact中&lt;/strong&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;PROC_HDR(PROCGLOBAL)结构体
 &lt;div id="proc_hdrprocglobal结构体" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#proc_hdrprocglobal%e7%bb%93%e6%9e%84%e4%bd%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;每个backend process都有proc结构体，很明显在高并发场景下扫描所有proc寻找事务信息比较耗时，这时需要一个实例级别的结构体存储所有proc信息，这个结构体就是PROCGLOBAL**。**&lt;/p&gt;
&lt;p&gt;源码一般用结构体类型PROC_HDR定义结构体指针指向PROCGLOBAL。PROC_HDR存储的是全局的proc信息，所有proc数组列表、空闲proc等等&lt;/p&gt;
&lt;p&gt;源码位置&lt;code&gt;src/include/storage/proc.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; PROC_HDR
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* pgproc数组 (not including dummies for prepared txns) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PGPROC	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;allProcs;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* pgxact数组 (not including dummies for prepared txns) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PGXACT	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;allPgXact;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Current shared estimate of appropriate spins_per_delay value */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			spins_per_delay;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* The proc of the Startup process, since not in ProcArray */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PGPROC	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;startupProc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			startupProcPid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Buffer id of the buffer that Startup process waits for pin on, or -1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			startupBufferPinWaitBufId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} PROC_HDR;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;PROCARRAY结构体
 &lt;div id="procarray结构体" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#procarray%e7%bb%93%e6%9e%84%e4%bd%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;procarray在&lt;code&gt;procarray.c&lt;/code&gt;中，&lt;code&gt;procarray.c&lt;/code&gt;是维护所有backend的PGPROC和PGXACT结构的。&lt;/p&gt;
&lt;p&gt;源码位置&lt;code&gt;src/backend/storage/ipc/procarray.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; ProcArrayStruct
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			numProcs;		&lt;span style="color:#75715e"&gt;/* proc的个数*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			maxProcs;		&lt;span style="color:#75715e"&gt;/* proc array的大小 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//处理已分配的xid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			maxKnownAssignedXids;	&lt;span style="color:#75715e"&gt;/* allocated size of array */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			numKnownAssignedXids;	&lt;span style="color:#75715e"&gt;/* current # of valid entries */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			tailKnownAssignedXids;	&lt;span style="color:#75715e"&gt;/* index of oldest valid element */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			headKnownAssignedXids;	&lt;span style="color:#75715e"&gt;/* index of newest element, + 1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;slock_t&lt;/span&gt;		known_assigned_xids_lck;	&lt;span style="color:#75715e"&gt;/* protects head/tail pointers */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Highest subxid that has been removed from KnownAssignedXids array to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * prevent overflow; or InvalidTransactionId if none. We track this for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * similar reasons to tracking overflowing cached subxids in PGXACT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * entries. Must hold exclusive ProcArrayLock to change this, and shared
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * lock to read it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId lastOverflowedXid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* oldest xmin of any replication slot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId replication_slot_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* oldest catalog xmin of any replication slot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId replication_slot_catalog_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* pgprocnos，相当于allPgXact[]数组下标，可用于检索allPgXact[]，该数组有PROCARRAY_MAXPROCS条目 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			pgprocnos[FLEXIBLE_ARRAY_MEMBER];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} ProcArrayStruct;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; ProcArrayStruct &lt;span style="color:#f92672"&gt;*&lt;/span&gt;procArray;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;获得快照&lt;/strong&gt;
 &lt;div id="获得快照" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%8e%b7%e5%be%97%e5%bf%ab%e7%85%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;GetTransactionSnapshot()
 &lt;div id="gettransactionsnapshot" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#gettransactionsnapshot" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;通过函数&lt;code&gt;GetTransactionSnapshot()&lt;/code&gt;获得快照&lt;/p&gt;
&lt;p&gt;源码&lt;code&gt;src/backend/utils/time/snapmgr.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// GetTransactionSnapshot()为一个事务中的sql分配合适的快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Snapshot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;GetTransactionSnapshot&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;// 如果是逻辑解码，则获得historic类型快照Return historic snapshot if doing logical decoding. We&amp;#39;ll never need a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#75715e"&gt;// 因为是逻辑解码事务，后续就不需要再call非historic类型快照了，直接return
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HistoricSnapshotActive&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;FirstSnapshotSet);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; HistoricSnapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 如果不是事务的第一次调用，则进入if */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;FirstSnapshotSet)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * 保证catalog快照是新的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;InvalidateCatalogSnapshot&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;pairingheap_is_empty&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;RegisteredSnapshots));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(FirstXactSnapshot &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果是并行模式下则返回报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsInParallelMode&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;elog&lt;/span&gt;(ERROR,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 &lt;span style="color:#e6db74"&gt;&amp;#34;cannot take query snapshot during a parallel operation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 &lt;span style="color:#75715e"&gt;//如果是可重复读或串行化隔离级别，则在事务中都使用同一个快照，所以只copy一次
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 &lt;span style="color:#75715e"&gt;//IsolationUsesXactSnapshot()标识隔离级别为可重复读或串行化，他们的在同事务中只使用一个快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsolationUsesXactSnapshot&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//首先，在CurrentSnapshotData中创建快照 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//如果是SI隔离级别，初始化SSI所需的数据结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsolationIsSerializable&lt;/span&gt;()) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				CurrentSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetSerializableTransactionSnapshot&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;CurrentSnapshotData);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				CurrentSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetSnapshotData&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;CurrentSnapshotData);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Make a saved copy */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* 可重复读或串行化隔离级别，这个快照会贯穿整个事务，所以只复制一次 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			CurrentSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CopySnapshot&lt;/span&gt;(CurrentSnapshot);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			FirstXactSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CurrentSnapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Mark it as &amp;#34;registered&amp;#34; in FirstXactSnapshot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			FirstXactSnapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;regd_count&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;pairingheap_add&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;RegisteredSnapshots, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;FirstXactSnapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;ph_node);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//如果是读已提交隔离级别，获得快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			CurrentSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetSnapshotData&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;CurrentSnapshotData);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修改标记，表示是第一次获得的快照，下次事务再调用该函数，就不会进到这层if了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		FirstSnapshotSet &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; CurrentSnapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//如果不是事务中第一次调用（已经有第一个快照了）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//可重复读或串行化隔离级别，返回第一个快照的复制品
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;IsolationUsesXactSnapshot&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; CurrentSnapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Don&amp;#39;t allow catalog snapshot to be older than xact snapshot. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;InvalidateCatalogSnapshot&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//读已提交级别，重新获得快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	CurrentSnapshot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetSnapshotData&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;CurrentSnapshotData);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; CurrentSnapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;关于&lt;code&gt;IsolationUsesXactSnapshot()&lt;/code&gt;和&lt;code&gt;IsolationIsSerializable()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;src/include/access/xact.h&lt;/code&gt;宏定义&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XACT_READ_UNCOMMITTED	0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XACT_READ_COMMITTED	1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XACT_REPEATABLE_READ	2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define XACT_SERIALIZABLE	3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//内部只有3个隔离级别，就是1、2、3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//2个隔离级别在每个事务中用同一快照，其他隔离级别在每个sql语句用一个快照
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define IsolationUsesXactSnapshot() (XactIsoLevel &amp;gt;= XACT_REPEATABLE_READ)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define IsolationIsSerializable() (XactIsoLevel == XACT_SERIALIZABLE)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;IsolationUsesXactSnapshot()&lt;/code&gt;是可重复读或串行化隔离级别&lt;/p&gt;
&lt;p&gt;&lt;code&gt;IsolationIsSerializable()&lt;/code&gt;是串行化隔离级别。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;GetTransactionSnapshot()&lt;/code&gt;函数流程图:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/578be2dea323.png" alt="在这里插入图片描述" /&gt;
（图片来自csdn &lt;a href="https://blog.csdn.net/Hehuyi_In" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GetTransactionSnapshot()&lt;/code&gt;主要的判断逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;逻辑解码时的historic快照直接返回快照结果&lt;/li&gt;
&lt;li&gt;在可重复读或串行化隔离级别，如果是第一次调用，返回快照并复制，以便下次（既非第一次）直接引用该快照&lt;/li&gt;
&lt;li&gt;在读已提交隔离级别，每次调用都生成新快照&lt;/li&gt;
&lt;li&gt;串行化隔离级别的第一次调用，额外获得SSI数据信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetTransactionSnapshot()&lt;/code&gt;获得快照，其获得快照数据调用的是&lt;code&gt;GetSnapshotData()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;GetSnapshotData()
 &lt;div id="getsnapshotdata" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#getsnapshotdata" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;源码&lt;code&gt;src/backend/storage/ipc/procarray.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Snapshot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;GetSnapshotData&lt;/span&gt;(Snapshot snapshot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//先初始化一些变量，包括arrayP指针，procarray，xmin，xmax，复制槽事务id等等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ProcArrayStruct &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arrayP &lt;span style="color:#f92672"&gt;=&lt;/span&gt; procArray;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId xmax;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId globalxmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			index;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			subcount &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;		suboverflowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId replication_slot_xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; InvalidTransactionId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId replication_slot_catalog_xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; InvalidTransactionId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(snapshot &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xip &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * First call for this snapshot. Snapshot is same size whether or not
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * we are in recovery, see later comments.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xip &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (TransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//获得当前事务的xip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;GetMaxSnapshotXidCount&lt;/span&gt;() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(TransactionId));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxip &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxip &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (TransactionId &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//获得当前子事务的subxip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;malloc&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;GetMaxSnapshotSubxidCount&lt;/span&gt;() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(TransactionId));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//获取procarray，需要共享lwlock锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;LWLockAcquire&lt;/span&gt;(ProcArrayLock, LW_SHARED);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* xmax=最大完成xid+1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	xmax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ShmemVariableCache&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;latestCompletedXid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(xmax));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;TransactionIdAdvance&lt;/span&gt;(xmax); &lt;span style="color:#75715e"&gt;//xmax+1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* xmax的值已经取出，xmin需要检索pgproc、pgxact、procarray */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 先把globalxmin、xmin赋值xmax，如果判断backend没有事务信息，就比较好办了 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	globalxmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmax; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//恢复快照单独处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;takenDuringRecovery &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RecoveryInProgress&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//非恢复快照需要到backend中获取事务信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;takenDuringRecovery)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;		 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pgprocnos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; arrayP&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pgprocnos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			numProcs;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * Spin over procArray checking xid, xmin, and subxids. The goal is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * to gather all active xids, find the lowest xmin, and try to record
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * subxids.看上去在检索procarray的时候会spin，以收集所有活跃的xid，最小的xmin，子事务subxid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		numProcs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; arrayP&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;numProcs;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (index &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; index &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; numProcs; index&lt;span style="color:#f92672"&gt;++&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			pgprocno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pgprocnos[index]; &lt;span style="color:#75715e"&gt;//通过循环numProcs进程个数，取pgprocno全部下标
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			PGXACT	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pgxact &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;allPgXact[pgprocno]; &lt;span style="color:#75715e"&gt;//通过pgprocno遍历所有pgxact结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			TransactionId xid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Update globalxmin to be the smallest valid xmin */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			xid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UINT32_ACCESS_ONCE&lt;/span&gt;(pgxact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmin);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(xid) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;NormalTransactionIdPrecedes&lt;/span&gt;(xid, globalxmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				globalxmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Fetch xid just once - see GetNewTransactionId */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			xid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UINT32_ACCESS_ONCE&lt;/span&gt;(pgxact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* 把backend中的xmin保存到快照xip中 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* 也就是说通过便利所有pgxact以找到所有活跃的xid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xip[count&lt;span style="color:#f92672"&gt;++&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* 子事务信息处理 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;suboverflowed) &lt;span style="color:#75715e"&gt;//如果子事务没有溢出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (pgxact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;overflowed)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					suboverflowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true; &lt;span style="color:#75715e"&gt;//如果事务溢出，将子事务也标记为溢出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			nxids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pgxact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nxids;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (nxids &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						PGPROC	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;proc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;allProcs[pgprocno];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#a6e22e"&gt;pg_read_barrier&lt;/span&gt;();	&lt;span style="color:#75715e"&gt;/* pairs with GetNewTransactionId */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#a6e22e"&gt;memcpy&lt;/span&gt;(snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxip &lt;span style="color:#f92672"&gt;+&lt;/span&gt; subcount,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) proc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxids.xids,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 nxids &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(TransactionId));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						subcount &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; nxids;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#75715e"&gt;//这里的else对应if (!snapshot-&amp;gt;takenDuringRecovery)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;// 这里的判断都是standby的，当实例是hot standby模式，从库中有查询事务时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		subcount &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;KnownAssignedXidsGetAndSetXmin&lt;/span&gt;(snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxip, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;xmin,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;												 xmax);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdPrecedesOrEquals&lt;/span&gt;(xmin, procArray&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lastOverflowedXid))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			suboverflowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//事物槽的xmin和catalog全集群xmin，先保存到本地变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//事物槽xmin是为了防止元组被回收
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//注释中说明是为了不长时间持有ProcArrayLock，才保存到本地变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	replication_slot_xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; procArray&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;replication_slot_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	replication_slot_catalog_xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; procArray&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;replication_slot_catalog_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//从backend中获取事务信息的工作已经完成，下面是一堆if判断，收尾工作并增加代码严谨性 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(MyPgXact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		MyPgXact&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TransactionXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;LWLockRelease&lt;/span&gt;(ProcArrayLock); &lt;span style="color:#75715e"&gt;//释放ProcArrayLock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdPrecedes&lt;/span&gt;(xmin, globalxmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		globalxmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmin; &lt;span style="color:#75715e"&gt;//globalxmin和进程xmin，globalxmin赋值更小的那个
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RecentGlobalXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; globalxmin &lt;span style="color:#f92672"&gt;-&lt;/span&gt; vacuum_defer_cleanup_age;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(RecentGlobalXmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		RecentGlobalXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FirstNormalTransactionId; &lt;span style="color:#75715e"&gt;//特殊情况下，如果RecentGlobalXmin&amp;lt;=2，赋值3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Check whether there&amp;#39;s a replication slot requiring an older xmin. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(replication_slot_xmin) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;NormalTransactionIdPrecedes&lt;/span&gt;(replication_slot_xmin, RecentGlobalXmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		RecentGlobalXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; replication_slot_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Non-catalog tables can be vacuumed if older than this xid */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RecentGlobalDataXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; RecentGlobalXmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//再次检查和对比catalog，globalxminn
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsNormal&lt;/span&gt;(replication_slot_catalog_xmin) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;NormalTransactionIdPrecedes&lt;/span&gt;(replication_slot_catalog_xmin, RecentGlobalXmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		RecentGlobalXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; replication_slot_catalog_xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	RecentXmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//开始给snapshot结构体赋值，返回快照数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xmax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xmax;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;xcnt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; count;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;subxcnt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; subcount;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;suboverflowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; suboverflowed;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetCurrentCommandId&lt;/span&gt;(false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果是一个新快照，初始化一些快照信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;active_count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;regd_count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;copied &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//下面是快照过久时的判断，居然写在这
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (old_snapshot_threshold &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * If not using &amp;#34;snapshot too old&amp;#34; feature, fill related fields with
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * dummy values that don&amp;#39;t require any locking.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果没有使用old_snapshot_threshold参数（参数&amp;lt;0，不会出现snapshot too old的问题）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//赋一些简单的值，都是常量，不会产生任何锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lsn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; InvalidXLogRecPtr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;whenTaken &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当old_snapshot_threshold参数&amp;gt;=0时，需要完成old snapshot的逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lsn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetXLogInsertRecPtr&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;//获得lsn
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;whenTaken &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetSnapshotCurrentTimestamp&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;//获得快照时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;MaintainOldSnapshotTimeMapping&lt;/span&gt;(snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;whenTaken, xmin); &lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//GetXLogInsertRecPtr()，GetSnapshotCurrentTimestamp() ,MaintainOldSnapshotTimeMapping()三个函数中有 //SpinLockAcquire和SpinLockRelease
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//MaintainOldSnapshotTimeMapping()函数还有LWLockAcquire和LWLockRelease 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//因为每次快照都要调用，获取快照数据函数应该是很频繁的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//所以能看出来pg13源码中，如果将old_snapshot_threshold设置为负数，spinlock和lwlock会少很多
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; snapshot;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;pg14对事务的优化
 &lt;div id="pg14对事务的优化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg14%e5%af%b9%e4%ba%8b%e5%8a%a1%e7%9a%84%e4%bc%98%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;pg14事务优化源码分析
 &lt;div id="pg14事务优化源码分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg14%e4%ba%8b%e5%8a%a1%e4%bc%98%e5%8c%96%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg13的源码能看出来&lt;code&gt;GetSnapshotData()&lt;/code&gt;中写死了&lt;code&gt;old_snapshot_threshold&amp;gt;=0&lt;/code&gt;时，每次获得快照数据都会产生较多的&lt;code&gt;SpinLock&lt;/code&gt;和&lt;code&gt;LWLock&lt;/code&gt;，而获得快照对于数据库来说是非常频繁的操作，这必定导致一些性能问题。所以pg14中直接把old_snapshot_threshold部分删除了···&lt;/p&gt;
&lt;p&gt;除了删除&lt;code&gt;GetSnapshotData()&lt;/code&gt;中的old_snapshot_threshold逻辑，还做了很多其他优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;移除&lt;code&gt;RecentGlobalXmin&lt;/code&gt;，&lt;code&gt;RecentGlobalDataXmin&lt;/code&gt;，新增&lt;code&gt;GlobalVisTest*&lt;/code&gt;系列函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新增边界boundaries概念，有两个边界分别为definitely_needed，maybe_needed&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; GlobalVisState
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* XIDs &amp;gt;= are considered running by some backend */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// &amp;gt;=definitely_needed的行一定可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	FullTransactionId definitely_needed;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* XIDs &amp;lt; are not considered to be running by any backend */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// &amp;lt;maybe_needed的行一定可以清理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	FullTransactionId maybe_needed;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新增&lt;code&gt;ComputeXidHorizons()&lt;/code&gt;用于进一步精准计算horizons（保存xmin和removable xid信息），该函数仍需要遍历PGPROC。计算的范围当然是在&lt;code&gt;XID &amp;gt;= maybe_needed &amp;amp;&amp;amp; XID &amp;lt; definitely_needed&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新增&lt;code&gt;GlobalVisTestShouldUpdate()&lt;/code&gt;用于判断是否需要再次计算边界&lt;/p&gt;
&lt;p&gt;先了解一个变量&lt;code&gt;ComputeXidHorizonsResultLastXmin&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; TransactionId ComputeXidHorizonsResultLastXmin; &lt;span style="color:#75715e"&gt;//最后一次精准计算的xmin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;GlobalVisTestShouldUpdate&lt;/span&gt;(GlobalVisState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;state)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//如果xmin=0，需要重新计算边界。相当于给初始化数据库产生的元组设置一个例外判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(ComputeXidHorizonsResultLastXmin))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * If the maybe_needed/definitely_needed boundaries are the same, it&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * unlikely to be beneficial to refresh boundaries.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//maybe_needed等于definitely_needed不需要再计算了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//不过不是用的等于，而是maybe_needed&amp;gt;=definitely_needed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//“大于”的场景是没有行一定可见，“等于”的场景是只有一行一定可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;FullTransactionIdFollowsOrEquals&lt;/span&gt;(state&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;maybe_needed,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 state&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;definitely_needed))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* does the last snapshot built have a different xmin? */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//当最后一次快照snapshot-&amp;gt;xmin=最后一次精准计算的xmin时，不再重新计算边界
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; RecentXmin &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; ComputeXidHorizonsResultLastXmin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看出maybe_needed和definitely_needed跟快照xmin、xmax是相似的，多嵌套了1层计算。先计算boundaries，再进一步精确计算horizons。GlobalVisTestShouldUpdate减少了计算boundaries的场景，而ComputeXidHorizons()精准计算也更高效。&lt;/p&gt;

&lt;h4 class="relative group"&gt;优化结果
 &lt;div id="优化结果" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bc%98%e5%8c%96%e7%bb%93%e6%9e%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;推荐一篇pg快照优化的文章：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462" target="_blank" rel="noreferrer"&gt;https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对比优化前后的效果相当明显：



&lt;img src="https://lastdba.com/img/csdn/a346095be5a7.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;其实在pg13的生产上也能看到GetSnapshotData的性能消耗总是很高。不过没截图，再借用下大佬的图&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8cd67db0e65f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;reference
 &lt;div id="reference" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#reference" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;books：
《postgresql指南 内幕探索》
《postgresql实战》
《postgresql技术内幕 事务处理深度探索》
《postgresql数据库内核分析》
&lt;a href="https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf" target="_blank" rel="noreferrer"&gt;https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf&lt;/a&gt;
官方资料：
&lt;a href="https://en.wikipedia.org/wiki/Concurrency_control" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Concurrency_control&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/Hint_Bits" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Hint_Bits&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/10/storage-page-layout.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/10/storage-page-layout.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/13/pageinspect.html3" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/pageinspect.html3&lt;/a&gt;
pg事务必读文章 interdb
&lt;a href="https://www.interdb.jp/pg/pgsql05.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05.html&lt;/a&gt;
&lt;a href="https://www.interdb.jp/pg/pgsql06.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql06.html&lt;/a&gt;
源码大佬
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/102920988" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/102920988&lt;/a&gt;
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/127955762" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/127955762&lt;/a&gt;
&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/125023923" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/125023923&lt;/a&gt;
pg的快照优化性能对比
&lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462" target="_blank" rel="noreferrer"&gt;https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462&lt;/a&gt;
其他资料
&lt;a href="https://brandur.org/postgres-atomicity" target="_blank" rel="noreferrer"&gt;https://brandur.org/postgres-atomicity&lt;/a&gt;
&lt;a href="https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;可见性检查
 &lt;div id="可见性检查" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8f%af%e8%a7%81%e6%80%a7%e6%a3%80%e6%9f%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;快照有了，就可以通过快照数据去判断元组的可见性。回顾一下（先不考虑子事务），事务的关键信息：元组头部事务信息、快照信息、clog事务状态(SetHintBits前需要）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;元组上有元组xmin、xmax、cmin、cmax、infomask等&lt;/li&gt;
&lt;li&gt;快照数据中有快照xmin、xmax、xip_list、curcid等&lt;/li&gt;
&lt;li&gt;clog中额外的事务状态信息，也可能写入了infomask中的hintbits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;快照类型不同，可见性判断略有区别&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;HeapTupleSatisfiesVisibility&lt;/span&gt;(HeapTuple tup, Snapshot snapshot, Buffer buffer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;snapshot_type)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SNAPSHOT_MVCC:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleSatisfiesMVCC&lt;/span&gt;(tup, snapshot, buffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; SNAPSHOT_NON_VACUUMABLE:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleSatisfiesNonVacuumable&lt;/span&gt;(tup, snapshot, buffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;每种快照都有各自的可见性规则，这里用最常见的SNAPSHOT_MVCC快照可见性规则来理解元组可见性&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;HeapTupleSatisfiesMVCC&lt;/span&gt;(HeapTuple htup, Snapshot snapshot,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 Buffer buffer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	HeapTupleHeader tuple &lt;span style="color:#f92672"&gt;=&lt;/span&gt; htup&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_data; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ItemPointerIsValid&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;htup&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_self)); &lt;span style="color:#75715e"&gt;//lp有效，也就是元组有效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(htup&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_tableOid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; InvalidOid); &lt;span style="color:#75715e"&gt;//oid有效，也就是表还有效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//t_xmin未提交，insert或update新元组的事务，未提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//在htup_details.h中已经宏定过，HeapTupleHeaderXminCommitted(）是((tup)-&amp;gt;t_infomask &amp;amp; HEAP_XMIN_COMMITTED) != 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//也就是说if (!HeapTupleHeaderXminCommitted(tuple)) 表示元组infomask中没有HEAP_XMIN_COMMITTED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//其实就是字面含义，t_xmin没有提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderXminCommitted&lt;/span&gt;(tuple)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//假如有个事务更新了元组，但是回退或者失败了，那么这个元组的xmin就是失败的事务ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果是失败事务的t_xmin，则直接返回不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderXminInvalid&lt;/span&gt;(tuple))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当元组infomask有HEAP_MOVED_OFF标记时，vacuum元组单独判断可见性，并对于vacuum事务做一些hintbits标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Used by pre-9.0 binary upgrades */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_MOVED_OFF)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			TransactionId xvac &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetXvac&lt;/span&gt;(tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(xvac))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(xvac, snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdDidCommit&lt;/span&gt;(xvac))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_INVALID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_COMMITTED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当元组infomask有HEAP_MOVED_IN标记时，vacuum元组单独判断可见性，并对于vacuum事务做一些hintbits标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Used by pre-9.0 binary upgrades */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_MOVED_IN)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			TransactionId xvac &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetXvac&lt;/span&gt;(tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(xvac))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(xvac, snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdDidCommit&lt;/span&gt;(xvac))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_COMMITTED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_INVALID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当元组是本事务写入的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmin&lt;/span&gt;(tuple)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetCmin&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid) &lt;span style="color:#75715e"&gt;//当元组cid&amp;gt;=快照事务当前commandid时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;	&lt;span style="color:#75715e"&gt;// 说明插入元组的时间晚于可见性检测开始时间，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_XMAX_INVALID) &lt;span style="color:#75715e"&gt;//当元组infomask位有HEAP_XMAX_INVALID时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true; &lt;span style="color:#75715e"&gt;//说明元组没有被删除（delete），元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//因为仅插入元组，不提交、提交或者回退，都是HEAP_XMAX_INVALID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//但是这个判断在“本事物写入”条件下,所以这里的逻辑是
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//本事务新增元组，未提交（逻辑上等价于同一事务中元组未被删除），且t_cid&amp;lt;curcid，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//xmax在两种情况被设置：1对元组加锁，元组被删除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//即使元组没有HEAP_XMAX_INVALID，可能也不是被删除，也可能是元组加锁了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//元组加锁情况下设置了xmax，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HEAP_XMAX_IS_LOCKED_ONLY&lt;/span&gt;(tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask))	&lt;span style="color:#75715e"&gt;/* not deleter */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;// HEAP_XMAX_IS_MULTI是对多个事务获取同一行锁时，才会产生MultiXactId
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;// 这里仍然是在判断xmax加锁情况下的可见性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_XMAX_IS_MULTI)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				TransactionId xmax;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				xmax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleGetUpdateXid&lt;/span&gt;(tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* not LOCKED_ONLY, so it has to have an xmax */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(xmax));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* updating subtransaction must have aborted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//如果xmax不是当前事务，则可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(xmax))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//如果xmax是当前事务，通过commandid判断，在更新和删除操作之前获得快照，在获得快照时间元组是可见的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetCmax&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;	&lt;span style="color:#75715e"&gt;/* updated after scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;	&lt;span style="color:#75715e"&gt;/* updated before scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//以下判断场景是：子事务中的删除命令回退了，需要SetHintBits为HEAP_XMAX_INVALID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//删除命令回退了，所以元组是可见的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* deleting subtransaction must have aborted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMAX_INVALID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//cmax删除元组的cid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//如果元组cmax&amp;gt;=快照curcid，则删除发生在快照扫描之后，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//如果元组cmax&amp;lt;快照curcid，则删除发生在快照扫描之前，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetCmax&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;	&lt;span style="color:#75715e"&gt;/* deleted after scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;	&lt;span style="color:#75715e"&gt;/* deleted before scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//XidInMVCCSnapshot()判断xid在快照生成时是in-progress状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//in-progress是 1.快照xmin&amp;lt;=xid&amp;lt;快照xmax且xid in xip_list 2.xid&amp;gt;=快照xmax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//以下XidInMVCCSnapshot()中的xid是t_xmin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//所以，这个判断的含义是：如果t_xmin在快照生成时是in-progress状态，则元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//相当于t_xmin没有提交，所以元组不可见。这看上去有点奇怪
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//因为整个判断是在!HeapTupleHeaderXminCommitted(tuple)下的，含义也是t_xmin没有提交，判断有些重复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//但是加上前面的几个小判断，这的else if就变得合理，其含义为：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//t_xmin没有提交，且元组没有被删除，且不是当前事务，则元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmin&lt;/span&gt;(tuple), snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果t_xmin事务提交了，做个SetHintBits为HEAP_XMIN_COMMITTED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//这里看上去有点奇怪，整个判断是t_xmin未提交的情况下，不应该出现t_xmin提交了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//而且，真的有这种情况的话，为什么这里不做事务可见性判断？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdDidCommit&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmin&lt;/span&gt;(tuple)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_COMMITTED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmin&lt;/span&gt;(tuple));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果t_xmin事务没有提交，做个SetHintBits为HEAP_XMIN_INVALID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* it must have aborted or crashed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMIN_INVALID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//t_xmin事务没有提交，再次返回不可见。看上去跟上面的关于XidInMVCCSnapshot()的条件很像
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当前即没有提交，又不满足XidInMVCCSnapshot()（xid在快照生成时不是in-progress）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//只有生成快照时事务未开始，后来事务开始了，目前没有提交，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//xmin未提交的情况下的事务可见性总算判断完了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//这里的else以后都是xmin提交的情况下，对元组可见性的判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//xmin已提交的判断是hintbits位有HEAP_XMIN_COMMITTED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//xmin已提交，但是不是当前快照做的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* xmin is committed, but maybe not according to our snapshot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//当infomask没有HEAP_XMIN_FROZEN且在快照生成时xmin in-progress状态，则元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//整合翻译一下，这里的if含义为快照生成时xmin未提交，在可见性判断时，元组xmin提交但没有标记FROZEN的情况，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//即使元组xmin已提交了，对当前快照而言仍然是in-progress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderXminFrozen&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmin&lt;/span&gt;(tuple), snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;		&lt;span style="color:#75715e"&gt;/* treat as still in progress */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//HEAP_XMAX_INVALID表示元组没有被删除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//这里的if含义是：当前元组提交了且在快照生成时也提交了且没有被删除（完全没有删除标记），元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_XMAX_INVALID)	&lt;span style="color:#75715e"&gt;/* xid invalid or aborted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//虽然元组上有xmax，但不是删除事务，而是锁标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//这里的if含义是：当前元组提交了且在快照生成时也提交了且有xmax，但xmax是锁标记，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HEAP_XMAX_IS_LOCKED_ONLY&lt;/span&gt;(tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//HEAP_XMAX_IS_MULTI表示元组处于shared-row-lock，一般表示多个事务处理一行时行所拥有的infomask标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_XMAX_IS_MULTI)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		TransactionId xmax;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* already checked above */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HEAP_XMAX_IS_LOCKED_ONLY&lt;/span&gt;(tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//获取更新元组的事务id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		xmax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeapTupleGetUpdateXid&lt;/span&gt;(tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* not LOCKED_ONLY, so it has to have an xmax */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Assert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;TransactionIdIsValid&lt;/span&gt;(xmax));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果shared-row-lock元组的事务ID是当前事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(xmax))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//元组cmax&amp;gt;=快照curcid时，元组在快照生成时还没有被删除，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetCmax&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;	&lt;span style="color:#75715e"&gt;/* deleted after scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//元组cmax&amp;lt;快照curcid时，元组在快照生成时还已被删除，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;	&lt;span style="color:#75715e"&gt;/* deleted before scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果shared-row-lock元组的事务ID不是当前事务，且在快照生成时xmax处于in-progress状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//这里的if含义是：xmin提交，且元组未被删除，有MULTI XMAX标记的情况下，xmax在快照生成时还未提交，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(xmax, snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果shared-row-lock元组事务已提交，则元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdDidCommit&lt;/span&gt;(xmax))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;		&lt;span style="color:#75715e"&gt;/* updating transaction committed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* it must have aborted or crashed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//更新元组异常终止或回滚，元组仍可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//元组xmin已提交，xmax还没有提交标记，还没有被删除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//看来!HEAP_XMAX_COMMITTED和HEAP_XMAX_INVALID还是有点区别
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//这里的判断看上去像元组经历过删除，但删除事务没有提交
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//而上面的HEAP_XMAX_INVALID是完全确认没有删除元组或删除abort or rollback，所以可以直接判断为true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;(tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_infomask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; HEAP_XMAX_COMMITTED))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果xmax与校验事务是同一事物
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TransactionIdIsCurrentTransactionId&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//还是老一套通过commandid检测可见性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//cmax&amp;gt;=快照curcid，说明删除在快照生成之后，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetCmax&lt;/span&gt;(tuple) &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; snapshot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;	&lt;span style="color:#75715e"&gt;/* deleted after scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//cmax&amp;lt;快照curcid，说明删除在快照生成之前，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;	&lt;span style="color:#75715e"&gt;/* deleted before scan started */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//删除事务没有提交，且xmax与校验事务不是同一事物
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//xmax在生成快照时是in-progress的，则元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple), snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//确认xmax删除事务回退或失败，SetHintBits为HEAP_XMAX_INVALID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//类似上面的HEAP_XMAX_INVALID，元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TransactionIdDidCommit&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* it must have aborted or crashed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMAX_INVALID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						InvalidTransactionId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* xmax transaction committed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//还剩下xmax删除事务已提交的场景，SetHintBits为HEAP_XMAX_COMMITTED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//按道理这里应该判断可见性，但是没有写在这，而是在代码的最后几行。因为这里的小条件属于大条件之一
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SetHintBits&lt;/span&gt;(tuple, buffer, HEAP_XMAX_COMMITTED,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* xmax is committed, but maybe not according to our snapshot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//xmax删除事务当前已提交，但是在快照生成时in-progress，则元组可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;XidInMVCCSnapshot&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HeapTupleHeaderGetRawXmax&lt;/span&gt;(tuple), snapshot))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; true;		&lt;span style="color:#75715e"&gt;/* treat as still in progress */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* xmax transaction committed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//只剩下xmax已提交的，且不在快照生成时in-progress的情况，元组不可见
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;整个可见性判断的源码看上去有点复杂。把SetHintBits部分刨去，省略繁杂的if，只看关键性的可见性规则，其中的关键点如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;可见性规则的主干逻辑&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除已提交，元组不可见&lt;/li&gt;
&lt;li&gt;插入已提交，删除回滚，元组可见&lt;/li&gt;
&lt;li&gt;插入已提交，删除未提交，本事务需要对比cid，其他事务对元组可见&lt;/li&gt;
&lt;li&gt;插入回滚，元组不可见&lt;/li&gt;
&lt;li&gt;插入未提交，同事务需要对比cmin，其他事务对元组不可见&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可见性检查中有两个时间点，一个是检查发生时间，一个是快照生成时间。判断逻辑就有同一个事务（检查事务和快照生成事务为同一事务）和不同事务（检查事务和快照生成事务为2个不同的事务）的情况&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果是同一事务，通过对比元组cmin/cmax和snapshot-&amp;gt;curcid的大小&lt;/p&gt;
&lt;p&gt;cmin&amp;gt;=snapshot-&amp;gt;curcid，说明插入元组的事务晚于快照获取时间，此时元组不可见。反之元组可见&lt;/p&gt;
&lt;p&gt;cmax&amp;gt;=snapshot-&amp;gt;curcid，说明删除元组的事务晚于快照获取时间，此时元组可见。反之元组不可见&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果不是同一事务，通过XidInMVCCSnapshot()函数判断xid(t_xmin或t_xmax）是否在快照生成时in-progress&lt;/p&gt;
&lt;p&gt;xmin在快照生成时in-progress，则元组不可见&lt;/p&gt;
&lt;p&gt;xmax在快照生成时in-progress，则元组可见&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;除了基本的dml操作，还需要完善其他条件下的判断，有如下4种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;vacuum事务删除和新增的元组可见性判断&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HEAP_XMAX_IS_LOCKED_ONLY锁标记时元组可见&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HEAP_XMAX_IS_MULTI元组处于multixact状态时的可见性判断&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;元组有frozen标记时的可见性判断&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;multixact
 &lt;div id="multixact" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#multixact" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;什么是multixact？
 &lt;div id="什么是multixact" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%afmultixact" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在对同一行加锁时，元组上关联的事务ID可能有多个，pg将多个事务ID组合起来用一个MultiXactID来管理。TransactionId和MultiXactID是多对一的关系&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ee67ad9bb95b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;multixactID跟TransactionId一样，也是32位，同样有wraparound&lt;/p&gt;
&lt;p&gt;MultiXactId的0、1都是系统使用，可分配的MultiXactId从2开始&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;源码&lt;/span&gt;src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;include&lt;span style="color:#f92672"&gt;/&lt;/span&gt;access&lt;span style="color:#f92672"&gt;/&lt;/span&gt;multixact.h
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define InvalidMultiXactId	((MultiXactId) 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define FirstMultiXactId	((MultiXactId) 1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MaxMultiXactId		((MultiXactId) 0xFFFFFFFF)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;行锁的类型&lt;/strong&gt;
 &lt;div id="行锁的类型" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%a1%8c%e9%94%81%e7%9a%84%e7%b1%bb%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;只有行上有锁时，才会有multixact。MultiXact总共定义了6种状态&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusForKeyShare &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x00&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusForShare &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x01&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusForNoKeyUpdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x02&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusForUpdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x03&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* an update that doesn&amp;#39;t touch &amp;#34;key&amp;#34; columns */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusNoKeyUpdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x04&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* other updates, and delete */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MultiXactStatusUpdate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x05&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} MultiXactStatus;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中能显示声明的行锁的状态有4种：ForKeyShare，ForShare，ForNoKeyUpdate，ForUpdate&lt;/p&gt;

&lt;h3 class="relative group"&gt;multixact的infomask标记
 &lt;div id="multixact的infomask标记" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#multixact%e7%9a%84infomask%e6%a0%87%e8%ae%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg会将行锁标记到xmax上并记录到infomask中
源码&lt;code&gt;src/include/access/htup_details.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_KEYSHR_LOCK	0x0010	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* xmax is a key-shared locker */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_EXCL_LOCK		0x0040	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* xmax is exclusive locker */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_LOCK_ONLY		0x0080	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* xmax, if valid, is only a locker */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_SHR_LOCK	(HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_LOCK_MASK	(HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;						 HEAP_XMAX_KEYSHR_LOCK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEAP_XMAX_IS_MULTI		0x1000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* t_xmax is a MultiXactId */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里重点模拟HEAP_XMAX_IS_MULTI标记，只有多个事务对同一行持有共享锁时才真正产生multixact id，才会有此标记&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--初始只有1行数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+----------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;742&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASNULL,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;窗口1&lt;/th&gt;
 &lt;th&gt;窗口2&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;lzldb=# begin; &lt;br /&gt; BEGIN &lt;br /&gt;lzldb=*# select * from lzl1 for share; &lt;br /&gt;a &lt;br /&gt;&amp;mdash; &lt;br /&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;lzldb=# begin; &lt;br /&gt; BEGIN &lt;br /&gt;lzldb=*# select * from lzl1 for share;&lt;br /&gt;a &lt;br /&gt;&amp;mdash; &lt;br /&gt;1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;lzldb=*# update lzl1 set a=2; &amp;ndash;hang&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;commit；&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UPDATE 1 &amp;ndash;update更新完成&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看元组xmax、infomask情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; t_ctid,lp,t_xmin,t_xmax,(t_infomask&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;)&lt;span style="color:#f92672"&gt;!=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; is_multixact &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; heap_page_items(get_raw_page(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; is_multixact 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+--------+--------+--------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;742&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;744&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;HEAP_XMAX_IS_MULTI的16进制值是1000，转换为10进制为4096，通过&lt;code&gt;(t_infomask&amp;amp;4096)!=0 is_multixact&lt;/code&gt;可以看出元组是否使用了multixact id。从上面的例子可以看出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multxact id不同于transaction id，它有自己的取值空间&lt;/li&gt;
&lt;li&gt;multixact id一般来说比transaction id小，所以这里t_xmax比t_xmin更小&lt;/li&gt;
&lt;li&gt;如果是一个update语句更新的元组，那么新旧元组的xmax肯定是相等的。但是在multixact的场景下，可能就不一样了。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;multixact slru
 &lt;div id="multixact-slru" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#multixact-slru" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;虽然&lt;code&gt;src/backend/access/transam/multixact.c&lt;/code&gt;的开头定义很多变量和函数，有&lt;code&gt;page&lt;/code&gt;,&lt;code&gt;member&lt;/code&gt;,&lt;code&gt;membergoup&lt;/code&gt;,&lt;code&gt;offset&lt;/code&gt;，但是总体都是定义变量值，然后定义这些变量进行相互转化的函数&lt;/p&gt;
&lt;p&gt;读懂&lt;code&gt;multixact.c&lt;/code&gt;前需要先了解几个宏定义&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/include/c.h中&lt;/code&gt;定义&lt;code&gt;MultiXactOffset&lt;/code&gt;是32位的类型&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; uint32 MultiXactOffset;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;src/include/access/slru.h中定义每个段有多少SLRU PAGES&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define SLRU_PAGES_PER_SEGMENT	32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;回到&lt;code&gt;src/backend/access/transam/multixact.c&lt;/code&gt;的开头&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;define &lt;span style="color:#a6e22e"&gt;MULTIXACT_OFFSETS_PER_PAGE&lt;/span&gt; (BLCKSZ &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(MultiXactOffset)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//MULTIXACT_OFFSETS_PER_PAGE=8k/32B=2048 一个page可以存储2048个offsets标识位,其实也是2048个MULTIXACTID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MultiXactIdToOffsetPage(xid) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//通过xid转换为对应记录的位于的页面：xid/2048
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MultiXactIdToOffsetEntry(xid) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//通过xid转换为对应记录位于页面的偏移量：xid%2048
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MultiXactIdToOffsetSegment(xid) (MultiXactIdToOffsetPage(xid) / SLRU_PAGES_PER_SEGMENT)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//通过xid转换为对应记录位于的segment：xid/2048/32
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再看下源码开头的注释&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Defines for MultiXactOffset page sizes. A page is the same BLCKSZ as is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * used everywhere else in Postgres.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Note: because MultiXactOffsets are 32 bits and wrap around at 0xFFFFFFFF,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * MultiXact page numbering also wraps around at
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE, and segment numbering at
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * take no explicit notice of that fact in this module, except when comparing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * segment and page numbers in TruncateMultiXact (see
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * MultiXactOffsetPagePrecedes).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为&lt;code&gt;MultiXactOffsets&lt;/code&gt;是32位且有wraparound，所以&lt;/p&gt;
&lt;p&gt;MultiXact页编号回卷于0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE=2^32^/2048=2^21&lt;/p&gt;
&lt;p&gt;段编号回卷于0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE/SLRU_PAGES_PER_SEGMENT=2^32^/2^11/^2^5^=2^16&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TruncateMultiXact()&lt;/code&gt;会清理这些段包括页编号，&lt;code&gt;TruncateMultiXact()&lt;/code&gt;被vacuum调用&lt;/p&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;pg_multixact目录&lt;/strong&gt;
 &lt;div id="pg_" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;同CLOG，SUBTRANS日志一样，multixact日志SLRU缓冲池实现。&lt;code&gt;pg_multixact&lt;/code&gt;目录下只有两个目录&lt;code&gt;member&lt;/code&gt;,&lt;code&gt;offset&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl pg_multixact&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 21:29 members
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 21:29 offsets&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一个mutixactid有对应多个transaction id，也就是member。offset是每个multiact的起始位置&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/39f86a3494b8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; mXactCacheEnt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MultiXactId multi; &lt;span style="color:#75715e"&gt;//一个MultiXactId
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;		nmembers;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	dlist_node	node;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]; &lt;span style="color:#75715e"&gt;//多个TransactionId，如果需要，pg用MultiXactIdExpand()扩展member
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} mXactCacheEnt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;multixact.h&lt;/code&gt;中定义了&lt;code&gt;MultiXactMember&lt;/code&gt;只是单个事务id和事务状态&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; MultiXactMember
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	TransactionId xid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	MultiXactStatus status;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} MultiXactMember;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;multixact参考
 &lt;div id="multixact参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#multixact%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/routine-vacuuming.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pgpedia.info/m/multixact-id.html" target="_blank" rel="noreferrer"&gt;https://pgpedia.info/m/multixact-id.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/15/explicit-locking.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/15/explicit-locking.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/14939" target="_blank" rel="noreferrer"&gt;https://www.modb.pro/db/14939&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.highgo.ca/2020/06/12/transactions-in-postgresql-and-their-mechanism/" target="_blank" rel="noreferrer"&gt;https://www.highgo.ca/2020/06/12/transactions-in-postgresql-and-their-mechanism/&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;2PC事务
 &lt;div id="2pc事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2pc%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;什么是2PC事务？
 &lt;div id="什么是2pc事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af2pc%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事务原子性要求事务必须整体完成或者回滚。在多个联接的数据库等情况下的分布式事务中，必须为事务提供一致性状态，以满足分布式事务的原子性。与其他数据库一样，pg库也提供了 two-phase commit protocol(2PC)两阶段提交协议。&lt;/p&gt;
&lt;p&gt;分布式事务实现方案很多，2PC是其中最基础也是最常见的。分布式事务包括原子提交、原子可见性、全局一致性，2PC只是原子提交的实现方案。&lt;/p&gt;

&lt;h3 class="relative group"&gt;prepare transaction
 &lt;div id="prepare-transaction" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#prepare-transaction" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;FDW可以自己处理2PC事务，pg也提供了显示使用2PC事务的方法prepare transaction。prepare transaction发起后，就不会与会话有任何关联，它状态会被保存下来。prepare transaction并不是设计为在应用或者交互式会话中使用，除非你在编写一个事务管理器，所以推荐（默认）关闭的。&lt;/p&gt;
&lt;p&gt;语法：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; transaction_id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt; PREPARED transaction_id 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt; PREPARED transaction_id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这的transaction_id不是内部事务id，只是一个声明的字符串&lt;/li&gt;
&lt;li&gt;PREPARE TRANSACTION 必须在事务块中，事务块以BEGIN|START STRANSATION开始&lt;/li&gt;
&lt;li&gt;max_prepared_transactions控制prepare事务数，默认为0关闭，需要打开才能使用prepare事务&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;开启一个prepare事务
 &lt;div id="开启一个prepare事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bc%80%e5%90%af%e4%b8%80%e4%b8%aaprepare%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_prepared_xacts ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; gid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; prepared &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;owner&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----+-------------------------------+-------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;719&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;866022&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt; prepared &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt; PREPARED 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_prepared_xacts ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; gid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; prepared &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;owner&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----+----------+-------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;pg_twophase目录
 &lt;div id="pg_twophase目录" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg_twophase%e7%9b%ae%e5%bd%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;前面说过，prepare事务与会话无关，当开启一个prepare事务后，事务状态信息保存在缓存中。
为了保证事务不丢失，prepare事务也会落盘，到&lt;code&gt;pg_twophase&lt;/code&gt;目录。
其实并不是关库才会导致prepare事务落盘，而是&lt;code&gt;checkpoint&lt;/code&gt;
源码&lt;code&gt;src/backend/access/transam/twophase.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;CheckPointTwoPhase&lt;/span&gt;(XLogRecPtr redo_horizon)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;TRACE_POSTGRESQL_TWOPHASE_CHECKPOINT_START&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;//checkpoint开始
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;fsync_fname&lt;/span&gt;(TWOPHASE_DIR, true); &lt;span style="color:#75715e"&gt;//调用fsync落盘
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;TRACE_POSTGRESQL_TWOPHASE_CHECKPOINT_DONE&lt;/span&gt;();&lt;span style="color:#75715e"&gt;//checkpoint完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;于是尝试开启一个prepare事务并做checkpoint&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzl pg_twophase]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;checkpoint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CHECKPOINT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[pg&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzl pg_twophase]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;rw&lt;span style="color:#75715e"&gt;------- 1 pg pg 116 Apr 29 16:33 000002D0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;orphaned prepared transactions
 &lt;div id="orphaned-prepared-transactions" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#orphaned-prepared-transactions" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果一个prepared事务没有完成（prepared事务不提交或回滚），而prepared事务又与会话无关，如果不显示结束这个事务的话，prepared事务仍然存在（会话断开后一般事务会回退），这就是orphaned prepared transactions。
orphaned prepared transactions会一直持有一些锁、元组的资源，导致vacuum无法回收和清理死元组，甚至阻止事务ID回卷。比如一个prepared事务忘记提交或者回滚了，如果没有外部事务管理机制来监控，这个parepared事务将可能不被发现并永远存在，最终导致严重的问题。所以建议&lt;code&gt;max_prepared_transactions=0&lt;/code&gt;（默认）或者通过&lt;code&gt;pg_prepared_xacts&lt;/code&gt;视图监控prepared事务&lt;/p&gt;
&lt;p&gt;下面模拟一个孤儿prepared事务无限期阻塞的情况&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--开启一个prepared事务并断开会话
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;q
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--会话断开prepared事务仍然存在
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_prepared_xacts ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; gid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; prepared &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;owner&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------+-----+-------------------------------+-------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;721&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;597678&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--ddl 阻塞
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b int;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看锁的情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; locktype,relation,pid,&lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_locks &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32808&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locktype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mode&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------+----------+-------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32808&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26136&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; AccessExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relation &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;32808&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; RowExclusiveLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--结束prepared事务，ddl执行完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt; prepared &lt;span style="color:#e6db74"&gt;&amp;#39;lzl&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt; PREPARED
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b int;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;2PC事务参考
 &lt;div id="2pc事务参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2pc%e4%ba%8b%e5%8a%a1%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://postgres.cn/docs/13/sql-prepare-transaction.html" target="_blank" rel="noreferrer"&gt;http://postgres.cn/docs/13/sql-prepare-transaction.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.highgo.ca/2020/01/28/understanding-prepared-transactions-and-handling-the-orphans/" target="_blank" rel="noreferrer"&gt;https://www.highgo.ca/2020/01/28/understanding-prepared-transactions-and-handling-the-orphans/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/Atomic_Commit_of_Distributed_Transactions" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Atomic_Commit_of_Distributed_Transactions&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;子事务
 &lt;div id="子事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%90%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;什么是子事务？
 &lt;div id="什么是子事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%ad%90%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一般事务只能整体提交或回滚，而子事务允许部分事务回滚。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SAVEPOINT p1 &lt;/code&gt;在事务里面打上保存点标记。不能直接提交子事务，子事务也是通过事务的提交而提交。不过可以通过&lt;code&gt;ROLLBACK TO SAVEPOINT p1&lt;/code&gt;回滚到该保存点。&lt;/p&gt;
&lt;p&gt;子事务在大批量数据写入的时候很有用。如果事务中存在多个子事务，而其中一小段子事务失败，只需要重做这小部分数据就行，而不需要整个事务数据全部重做。&lt;/p&gt;

&lt;h3 class="relative group"&gt;子事务在SQL语句中的使用
 &lt;div id="子事务在sql语句中的使用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%90%e4%ba%8b%e5%8a%a1%e5%9c%a8sql%e8%af%ad%e5%8f%a5%e4%b8%ad%e7%9a%84%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SAVEPOINT savepoint_name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt; [ &lt;span style="color:#66d9ef"&gt;WORK&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRANSACTION&lt;/span&gt; ] &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; [ SAVEPOINT ] savepoint_name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RELEASE [ SAVEPOINT ] savepoint_name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;savepoints语句必须在事务块中&lt;/li&gt;
&lt;li&gt;savepoint执行保存点；rollback回滚到指定保存点；release擦除保存点，不会回滚子事务数据&lt;/li&gt;
&lt;li&gt;cursor不会被savepoint事务影响&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;sql中的子事务示例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; savepoint p1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SAVEPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; savepoint p2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SAVEPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; savepoint p3;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SAVEPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; lzl1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rollback&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; savepoint p2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ROLLBACK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=*#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COMMIT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; xmin,xmax,cmin,a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; a 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------+------+------+---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;731&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;732&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--回滚到p2时，p3也被回滚
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; vlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; t_cid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; raw_flags &lt;span style="color:#f92672"&gt;|&lt;/span&gt; combined_flags 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--------+----+-----------+--------+--------+-------+------------------------------------------------------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;731&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;732&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;733&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASNULL,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;734&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASNULL,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--子事务infomask跟一般事务区别不大，同一个事务中多个命令通过cid和HEAP_XMIN_INVALID等就可以判断可见性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--子事务产生写入同样会消耗transaction id，而且cid在父事务框架下增加&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;&lt;strong&gt;其他场景中产生子事务&lt;/strong&gt;
 &lt;div id="其他场景中产生子事务" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b6%e4%bb%96%e5%9c%ba%e6%99%af%e4%b8%ad%e4%ba%a7%e7%94%9f%e5%ad%90%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;即使不用&lt;code&gt;savepoint&lt;/code&gt;，也有其他方法产生子事务&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EXCEPTION&lt;/code&gt;语句会触发子事务，这在一些工具或架构中常见，也很容易被忽略。每次&lt;code&gt;EXCEPTION&lt;/code&gt;都会产生一个子事务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;语法如：&lt;code&gt;BEGIN / EXCEPTION WHEN .. / END&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;参考：&lt;a href="https://fluca1978.github.io/2020/02/05/PLPGSQLExceptions.html" target="_blank" rel="noreferrer"&gt;https://fluca1978.github.io/2020/02/05/PLPGSQLExceptions.html&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PL/Python代码引用plpy.subtransaction()&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;子事务SLRU缓存
 &lt;div id="子事务slru缓存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%90%e4%ba%8b%e5%8a%a1slru%e7%bc%93%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;子事务提交日志在&lt;code&gt;pg_xact&lt;/code&gt;，父子对应关系在&lt;code&gt;pg_subtrans&lt;/code&gt;存储子事务缓存subXID和父XID的映射。当PostgreSQL需要查找subXID时，它会计算这个ID驻留在哪个内存页中，然后在内存页中进行搜索。如果页面不在缓存中，它会驱逐一个页面，并将所需的页面从pg_subtrans加载到内存中。大量的子事务cache miss会消耗系统的IO和cpu。&lt;/p&gt;
&lt;p&gt;子事务用的buffer只有32个并在源码中写死&lt;/p&gt;
&lt;p&gt;源码&lt;code&gt;src/include/access/subtrans.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* Number of SLRU buffers to use for subtrans */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\#&lt;/span&gt;define NUM_SUBTRANS_BUFFERS &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;buffer默认为8k，xid是32位占4个bytes，所以&lt;/p&gt;
&lt;p&gt;SUBTRANS_BUFFER大小为32*8k=256k&lt;/p&gt;
&lt;p&gt;SUBTRANS_BUFFER能存储最多32*8k/4=65536个xid&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f1a4a6d13c77.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;通过transactionid找到子事务的在page中的位置
源码&lt;code&gt;src/backend/access/transam/subtrans.c&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* We need four bytes per xact */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//每个页面最多存储8k/4bytes=2048个子事务id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToPage(xid) ((xid) / (TransactionId) SUBTRANS_XACTS_PER_PAGE)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//通过子事务xid计算page号=xid/2048
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//通过子事务xid计算在page中的offset=xid%2048
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;子事务xid在page中不一定是紧凑的，一个page可能少于2048个子事务id&lt;/p&gt;

&lt;h3 class="relative group"&gt;子事务的危害
 &lt;div id="子事务的危害" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%90%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%8d%b1%e5%ae%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PGPROC_MAX_CACHED_SUBXIDS溢出&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;PGPROC_MAX_CACHED_SUBXIDS&lt;/code&gt;不是GUI参数，在源码中写死，只能通过改源码修改该参数。&lt;/p&gt;
&lt;p&gt;源码&lt;code&gt;src/include/storage/proc.h&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*每个backend都有子事务cache上限PGPROC_MAX_CACHED_SUBXIDS。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*我们必须跟踪cache是否溢出（比如，事务至少有一个缓存不了的子事务）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*如果一个cache都没有溢出，我们可以确认没有在pgproc array中xid一定不是一个运行中的事务。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*（没有在任何proc，又没有溢出，说明没有跑）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*如果有溢出，我们必须查看pg_subtrans
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;#define PGPROC_MAX_CACHED_SUBXIDS 64	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* XXX guessed-at value */&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; XidCache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;阅读这段源码，得到两个重要信息&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个backend都有子事务cache为&lt;code&gt;PGPROC_MAX_CACHED_SUBXIDS&lt;/code&gt;，固定64个子事务&lt;/li&gt;
&lt;li&gt;超过64个子事务会溢出到&lt;code&gt;pg_subtrans&lt;/code&gt;目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;copy大佬压测：子事务刚好超过64个的时候，性能下降。所以，每个会话的子事务最好不要超过64个&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6ac0dc4add28.png" alt="在这里插入图片描述" /&gt;
参考：&lt;a href="https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful" target="_blank" rel="noreferrer"&gt;https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful&lt;/a&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;子事务导致multixact异常等待&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;原文：&lt;a href="https://buttondown.email/nelhage/archive/notes-on-some-postgresql-implementation-details/" target="_blank" rel="noreferrer"&gt;https://buttondown.email/nelhage/archive/notes-on-some-postgresql-implementation-details/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for update&lt;/code&gt;本身是行级排他锁，本身不应该产生multixact id，但在此场景中产生了多个MultiXact等待，导致数据库性能断崖&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LWLock:MultiXactMemberControlLock&lt;/li&gt;
&lt;li&gt;LWLock:MultiXactOffsetControlLock&lt;/li&gt;
&lt;li&gt;LWLock:multixact_member&lt;/li&gt;
&lt;li&gt;LwLock:multixact_offset&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后来发现在Django框架中有子事务语句&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;some&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SAVEPOINT save;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; [the same &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;从库性能急剧下降&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;原文：&lt;a href="https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/" target="_blank" rel="noreferrer"&gt;https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一个长事务和一个savepoint子事务也可能造成查询库性能断崖&lt;/p&gt;
&lt;p&gt;如果读取发生在主库的快照上，则生成的快照包含xmin，xmax，txip事务列表，subxip保存一个在进行的子事务列表。&lt;strong&gt;但是，无论是原数组还是快照都不会直接与从库共享，从库从WAL中读取所需的所有数据&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a4c7e36c274a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;当存在子事务时，一个长事务的运行会使从库性能断崖式下滑&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/06211a3788ce.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;生产性能急剧下降&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当数据库运行繁忙，又存在较多子事务时，性能可能急剧下降，并伴随子事务的等待事件。这个场景即使每个会话子事务没有超过64，而且不是在从库而是在主库上时，也会发生。&lt;/p&gt;
&lt;p&gt;我们发现工具（OGG）中默认是50个子事务，此时我们将工具中的子事务数据量降低到10-20个时，数据库性能得到缓解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;子事务的使用建议&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;除了显示savepoint使用子事务，excetpion、框架、工具中同样会产生子事务&lt;/li&gt;
&lt;li&gt;如果有从库查询业务，禁止使用子事务。&lt;/li&gt;
&lt;li&gt;谨慎使用行锁。for update+子事务同样会引起multixactid的问题&lt;/li&gt;
&lt;li&gt;如果仍有子事务，子事务设置不要超过64个，最好是更低&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;子事务已经在国内外生产环境造成了非常多问题，有许多案例和问题分析。引用一下“Subtransactions are basically cursed. Rip em out.”&lt;/p&gt;

&lt;h3 class="relative group"&gt;子事务参考
 &lt;div id="子事务参考" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ad%90%e4%ba%8b%e5%8a%a1%e5%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful" target="_blank" rel="noreferrer"&gt;https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cybertec-postgresql.com/en/subtransactions-and-performance-in-postgresql/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/subtransactions-and-performance-in-postgresql/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://fluca1978.github.io/2020/02/05/PLPGSQLExceptions.html" target="_blank" rel="noreferrer"&gt;https://fluca1978.github.io/2020/02/05/PLPGSQLExceptions.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/" target="_blank" rel="noreferrer"&gt;https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://buttondown.email/nelhage/archive/notes-on-some-postgresql-implementation-details/" target="_blank" rel="noreferrer"&gt;https://buttondown.email/nelhage/archive/notes-on-some-postgresql-implementation-details/&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;reference
 &lt;div id="reference-1" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#reference-1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;books：&lt;/p&gt;
&lt;p&gt;《postgresql指南 内幕探索》&lt;/p&gt;
&lt;p&gt;《postgresql实战》&lt;/p&gt;
&lt;p&gt;《postgresql技术内幕 事务处理深度探索》&lt;/p&gt;
&lt;p&gt;《postgresql数据库内核分析》&lt;/p&gt;
&lt;p&gt;&lt;a href="https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf" target="_blank" rel="noreferrer"&gt;https://edu.postgrespro.com/postgresql_internals-14_parts1-2_en.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;官方资料：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Concurrency_control" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Concurrency_control&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.postgresql.org/wiki/Hint_Bits" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Hint_Bits&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/10/storage-page-layout.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/10/storage-page-layout.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/13/pageinspect.html3" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/pageinspect.html3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pg事务必读文章 interdb&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/pgsql05.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/pgsql06.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql06.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;源码大佬&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/102920988" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/102920988&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/127955762" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/127955762&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/125023923" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/125023923&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pg的快照优化性能对比&lt;/p&gt;
&lt;p&gt;&lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462" target="_blank" rel="noreferrer"&gt;https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/improving-postgres-connection-scalability-snapshots/ba-p/1806462&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其他资料&lt;/p&gt;
&lt;p&gt;&lt;a href="https://brandur.org/postgres-atomicity" target="_blank" rel="noreferrer"&gt;https://brandur.org/postgres-atomicity&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/j-8uRuZDRf4mHIQR_ZKIEg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/postgrechina/article/details/49130743?spm=a2c6h.12873639.article-detail.7.41b32cda2KR1QM" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/postgrechina/article/details/49130743?spm=a2c6h.12873639.article-detail.7.41b32cda2KR1QM&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mysql.taobao.org/monthly/2018/12/02/" target="_blank" rel="noreferrer"&gt;http://mysql.taobao.org/monthly/2018/12/02/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>向量数据库相关概念</title><link>https://lastdba.com/2024/08/12/%E5%90%91%E9%87%8F%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E5%90%91%E9%87%8F%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5/</guid><description>&lt;h2 class="relative group"&gt;向量数据库相关概念
 &lt;div id="向量数据库相关概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9b%b8%e5%85%b3%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;亿点点历史知识
 &lt;div id="亿点点历史知识" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%bf%e7%82%b9%e7%82%b9%e5%8e%86%e5%8f%b2%e7%9f%a5%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LLM的模型发展历史，&lt;a href="https://arxiv.org/pdf/2304.13712" target="_blank" rel="noreferrer"&gt;Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;向量数据库相关概念
 &lt;div id="向量数据库相关概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9b%b8%e5%85%b3%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;亿点点历史知识
 &lt;div id="亿点点历史知识" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%ba%bf%e7%82%b9%e7%82%b9%e5%8e%86%e5%8f%b2%e7%9f%a5%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LLM的模型发展历史，&lt;a href="https://arxiv.org/pdf/2304.13712" target="_blank" rel="noreferrer"&gt;Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6913a42c261b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;很多人都是从ChatGPT爆点后才逐渐了解到大模型，但在爆点的前几年大模型的发展已经开始了诸神之战。一些机构发布了许多革命性的论文，公司部分像是Google、DeepMind、OpenAI、Meta、Microsoft，学校部分像是Stanford、Berkeley、CMU、Princeton、MIT&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;总共分为三个阵营：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google和DeepMind阵营 — Gemini、Bard&lt;/li&gt;
&lt;li&gt;Microsoft和OpenAI阵营 —ChatGPT、Bing&lt;/li&gt;
&lt;li&gt;Meta开源社区阵营 — Llama&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;近几年现有大模型产品发布时间线&lt;a href="https://arxiv.org/pdf/2303.18223.pdf" target="_blank" rel="noreferrer"&gt;A Survey of Large Language Models&lt;/a&gt;&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/517ff3855241.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;生成式AI的简单概念
 &lt;div id="生成式ai的简单概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%94%9f%e6%88%90%e5%bc%8fai%e7%9a%84%e7%ae%80%e5%8d%95%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;AIGC（Artificial Intelligence generated Content）&lt;/strong&gt;：AIGC精准概念是利用AI自动生成内容的生产方式。广义的AIGC可以近似训练像人类一样具备生成创建能力的AI技术，即生成式AI，它可以基于数据和生成演算法模型，自主生成创建新的文本、图像、音乐、视频、3D交互内容等各种形式的内容和数据，以及包括开启科学新发现、创造新的和意义等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLM（Large Language Model）&lt;/strong&gt;：LLM即大语言模型，LLM能够捕捉和处理复杂的语言模式和语义，也就是它能够理解和生成人类语言。GPT3、ChatGPT、BERT、T5、文心一言等都是典型的大型语言模型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NLP（Natural language processing）&lt;/strong&gt;：自然语言处理（NLP）是研究如何让计算机读懂人类语言，也就是将人的自然语言转换为计算机可以阅读的指令。LLM是 NLP 中的一个重要组成部分。&lt;/p&gt;
&lt;p&gt;AIGC取得了令人瞩目的增长，有很大因素就在于自然语言处理（NLP），而推动NLP发展的最大功臣是大语言模型（LLM）。今年（2024年）AIGC在视频、声音等领域也同样发展迅速。&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;prompt&lt;/strong&gt;：提示符、指令，提供给AI对应描述任务的自然语言，用于引导语言模型（如GPT-3或GPT-4）生成相应的输出&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;。（大伙其实都知道是啥了，不多解释）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;embedding&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;嵌入是一种表示对象（如文本、图像和音频）的方法，将其表示为连续向量空间中的点，这些点在空间中的位置对机器学习算法具有语义。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/3449199f0a3f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;根据&lt;a href="https://nlp.stanford.edu/projects/glove/" target="_blank" rel="noreferrer"&gt;GloVe&lt;/a&gt;英文单词和向量相关性，这有个可&lt;a href="https://blog.echen.me/embedding-explorer/#/" target="_blank" rel="noreferrer"&gt;直接看词汇embedding后的二维图&lt;/a&gt;。这个就是自然语言嵌入为二维向量：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/97b468b62314.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;RAG
 &lt;div id="rag" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rag" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;RAG(Retrieval-Augmented Generation)是一个包含文档检索和大型语言模型（LLM）回答生成的两阶段过程。初始阶段利用密集嵌入来检索文档。根据具体使用场景，这种检索可以基于多种数据库格式，例如向量数据库、摘要索引、树索引、key索引&lt;sup id="fnref1:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6eb500130d41.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/2005.11401" target="_blank" rel="noreferrer"&gt;RAG原始论文&lt;/a&gt;&lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;是2020年5月22日发布，来自Facebook(Meta)、伦敦大学学院、纽约大学的人员提出RAG的通用微调方法 。RAG包含如下特性&lt;sup id="fnref1:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RAG模型结合了预训练的记忆以帮助语言的生成&lt;/li&gt;
&lt;li&gt;RAG模型生成的语言更加具体、多样且具有事实性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6ed7b3a3ae81.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;OpenAI在2023年3月23日发布的&lt;a href="https://github.com/openai/chatgpt-retrieval-plugin" target="_blank" rel="noreferrer"&gt;chatgpt-retrieval-plugin&lt;/a&gt;仓库推荐在RAG中使用向量数据库，从此在应用领域向量数据库跟随大模型的爆火而备受关注&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b58b99f55a52.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;向量数据库能为AI带来什么？
 &lt;div id="向量数据库能为ai带来什么" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e8%83%bd%e4%b8%baai%e5%b8%a6%e6%9d%a5%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;向量数据库能在RAG中为大模型提供数据检索和数据长期存储的能力&lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f35b1bc4881b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;为什么要使用RAG？任何话语都没有祖师爷OpenAI说话有力。下面一段话源自2023年3月OpenAI的发布的检索插件使用指引&lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt;，用ChatGPT翻译如下：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;开源检索插件使 ChatGPT 能够访问个人或组织的信息源（需获得许可）。用户可以通过自然语言提问或表达需求，从其数据源（如文件、笔记、电子邮件或公共文档）中获取最相关的文档片段。&lt;/p&gt;
&lt;p&gt;作为开源且自托管的解决方案，开发者可以部署他们自己的插件版本并注册到 ChatGPT 上。该插件利用 OpenAI 的嵌入技术，并允许开发者选择一个矢量数据库（如 Milvus、Pinecone、Qdrant、Redis、Weaviate 或 Zilliz）来索引和搜索文档。信息源可以使用 webhook 与数据库同步。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;总之，OpenAI推荐大伙使用向量数据库。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/0eBZ4zyX6XjBQO0GqlANnw" target="_blank" rel="noreferrer"&gt;向量数据库凉了吗？&lt;/a&gt;不仅没有凉，RAG发展到今天，甚至都已经烂大街了&amp;ndash;&lt;a href="https://mp.weixin.qq.com/s/awIInAtPOkZz_s4jg9TO_w" target="_blank" rel="noreferrer"&gt;RAG 技术真的“烂大街”了吗？&lt;/a&gt;。而向量数据库因具有高检索效率、数据存储可靠性等等特点，是RAG的重要一环。&lt;/p&gt;

&lt;h3 class="relative group"&gt;常见的向量数据库
 &lt;div id="常见的向量数据库" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%b8%b8%e8%a7%81%e7%9a%84%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;自从OpenAI发布RAG repo以来，出现了许多向量数据库（当然以前也有一些）。一些公司也拿到了相当可观的融资&lt;sup id="fnref:9"&gt;&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref"&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;Company&lt;/th&gt;
 &lt;th style="text-align: left"&gt;Headquartered in&lt;/th&gt;
 &lt;th style="text-align: left"&gt;Funding&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Weaviate&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇳🇱 Amsterdam&lt;/td&gt;
 &lt;td style="text-align: left"&gt;$68M Series B&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Qdrant&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇩🇪 Berlin&lt;/td&gt;
 &lt;td style="text-align: left"&gt;$11M Seed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Pinecone&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇺🇸 San Francisco&lt;/td&gt;
 &lt;td style="text-align: left"&gt;$138M Series B&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Milvus/Zilliz&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇨🇳 / 🇺🇸 Redwood City&lt;/td&gt;
 &lt;td style="text-align: left"&gt;$113M Series B&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Chroma&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇺🇸 San Francisco&lt;/td&gt;
 &lt;td style="text-align: left"&gt;$20M Seed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;LanceDB&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇺🇸 San Francisco&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Venture&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Vespa&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇳🇴 / 🇺🇸 Indianapolis&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Yahoo!&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Vald&lt;/td&gt;
 &lt;td style="text-align: left"&gt;🇯🇵 Tokyo&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Yahoo! Japan&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;向量数据库发布时间：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/87c1f32c95b1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/erikbern/ann-benchmarks" target="_blank" rel="noreferrer"&gt;向量数据库性能对比&lt;/a&gt;&lt;sup id="fnref:10"&gt;&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref"&gt;10&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5d6c1d0ba8c2.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;专用向量数据库一般来说比插件来实现向量的传统数据库性能更好，原因大概有两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专用向量数据库针对向量做的底层存储，其性能一般都要好于无目标性的传统数据库&lt;/li&gt;
&lt;li&gt;专用向量数据库一般更新（基本都是go、rust实现的），他们在代码实现层面更方便优化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但这不代表插件实现的向量数据库没有用武之地：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传统数据库原生就支持更多功能，不仅仅是相似度计算&lt;/li&gt;
&lt;li&gt;ACID，传统数据库的存储更为安全&lt;/li&gt;
&lt;li&gt;在同一个数据库中更容易操作数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;向量数据功能对比：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c1f5f45fa343.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pgvector/pgvector" target="_blank" rel="noreferrer"&gt;上面对pgvector&lt;/a&gt;的描述不太准确了，pgvector目前已经支持了HNSW，基于pgvector的生态&lt;a href="https://github.com/timescale/pgvectorscale" target="_blank" rel="noreferrer"&gt;pgvectorscale&lt;/a&gt;也支持了DiskANN。&lt;/p&gt;

&lt;h2 class="relative group"&gt;数学相关概念
 &lt;div id="数学相关概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%95%b0%e5%ad%a6%e7%9b%b8%e5%85%b3%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;数学说：“我站在山顶看你们玩”&lt;/em&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;标量&lt;/strong&gt;
 &lt;div id="标量" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%a0%87%e9%87%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;标量就是具体的数。标量没有方向，一般是相对向量来定义的。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;向量（vector）&lt;/strong&gt;
 &lt;div id="向量vector" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%91%e9%87%8fvector" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;在欧几里得空间中，向量包括长度和方向。如下点&lt;em&gt;A&lt;/em&gt;到点&lt;em&gt;B&lt;/em&gt;的向量&lt;strong&gt;a&lt;/strong&gt;（包含两个点的信息，和方向信息）&lt;sup id="fnref:11"&gt;&lt;a href="#fn:11" class="footnote-ref" role="doc-noteref"&gt;11&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fa984d43877f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;单位向量（Unit vector）&lt;/strong&gt;
 &lt;div id="单位向量unit-vector" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%8d%95%e4%bd%8d%e5%90%91%e9%87%8funit-vector" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;大小为一个单位的向量就是单位向量。单位向量等于向量除以欧几里得长度&lt;sup id="fnref:12"&gt;&lt;a href="#fn:12" class="footnote-ref" role="doc-noteref"&gt;12&lt;/a&gt;&lt;/sup&gt;：
$$
\vec a = \frac{\mathbf a}{||\mathbf a||}
$$&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e9563146f301.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;数学中的单位向量（&lt;a href="https://en.wikipedia.org/wiki/Unit_vector" target="_blank" rel="noreferrer"&gt;Unit vector&lt;/a&gt;）在pgvector和OpenAI embeddings中被称为normalized vector。（注意，不要跟数学中的normal vector混淆，&lt;a href="https://en.wikipedia.org/wiki/Normal_%28geometry%29" target="_blank" rel="noreferrer"&gt;normal vector&lt;/a&gt;是法向量，是另一个概念）&lt;/p&gt;
&lt;p&gt;&lt;em&gt;为什么要使用单位向量？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;OpenAI embeddings对使用单位向量的解释&lt;sup id="fnref:13"&gt;&lt;a href="#fn:13" class="footnote-ref" role="doc-noteref"&gt;13&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;OpenAI embeddings are normalized to length 1, which means that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cosine similarity can be computed slightly faster using just a dot product&lt;/li&gt;
&lt;li&gt;Cosine similarity and Euclidean distance will result in the identical rankings&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4 class="relative group"&gt;&lt;strong&gt;稀疏向量（sparse vector）&lt;/strong&gt;
 &lt;div id="稀疏向量sparse-vector" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%a8%80%e7%96%8f%e5%90%91%e9%87%8fsparse-vector" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;稀疏向量之所以称为稀疏向量，是因为向量中的信息分布稀疏。通常情况下，我们需要在成千上万个零中找到几个1（相关信息）。因此，这些向量可以包含许多维度，通常在数万个维度。&lt;/p&gt;
&lt;p&gt;稀疏向量和密集向量的比较。稀疏向量包含稀疏分布的信息位，而密集向量在每个维度上都包含更多信息，信息密集。&lt;sup id="fnref:14"&gt;&lt;a href="#fn:14" class="footnote-ref" role="doc-noteref"&gt;14&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6d7500917874.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;欧几里得空间（Euclidean space）&lt;/strong&gt;
 &lt;div id="欧几里得空间euclidean-space" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%ac%a7%e5%87%a0%e9%87%8c%e5%be%97%e7%a9%ba%e9%97%b4euclidean-space" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;简称欧式空间，是数学中最基本的空间。现代数学中，正整数n维的空间称为欧几里得空间。&lt;/p&gt;
&lt;p&gt;还有一些其他的空间定义，如内积空间、希尔伯特空间，它们在数学定义上有不同，但是在数据库/真实世界中不会分那么清楚，基本要知道的是内积空间、欧几里得空间、希尔伯特空间都可以包含点、向量、内积等元素，我们可以简单的称他们为“&lt;strong&gt;多维空间&lt;/strong&gt;”。它们的区别可参考&lt;a href="https://zhuanlan.zhihu.com/p/684643954" target="_blank" rel="noreferrer"&gt;漫谈数学中的各种空间&lt;/a&gt;&lt;sup id="fnref:15"&gt;&lt;a href="#fn:15" class="footnote-ref" role="doc-noteref"&gt;15&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a22c1c460ef1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;欧几里得距离(Euclidean distance)&lt;/strong&gt;
 &lt;div id="欧几里得距离euclidean-distance" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%ac%a7%e5%87%a0%e9%87%8c%e5%be%97%e8%b7%9d%e7%a6%bbeuclidean-distance" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;简称欧式距离，也就是我们一般认为的点与点的距离，即线段的长度&lt;sup id="fnref:16"&gt;&lt;a href="#fn:16" class="footnote-ref" role="doc-noteref"&gt;16&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/15196bf76dd3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;在二维空间中，点q与点p的欧式距离为：
$$
d(\mathbf p,\mathbf q)=\sqrt{(p_1-q_1)^2+(p_2-q_2)^2}
$$&lt;/p&gt;
&lt;p&gt;在n维空间中，点q与点p的欧式距离为：
$$
d(\mathbf p,\mathbf q)=\sqrt{(p_1-q_1)^2+(p_2-q_2)^2+\cdots+(p_n-q_n)^2}
$$&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;曼哈顿距离（Manhattan distance OR Taxicab distance）&lt;/strong&gt;
 &lt;div id="曼哈顿距离manhattan-distance-or-taxicab-distance" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%9b%bc%e5%93%88%e9%a1%bf%e8%b7%9d%e7%a6%bbmanhattan-distance-or-taxicab-distance" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;$$
d(\mathbf p,\mathbf q)= \sum_{i=1}^n | p_i-q_i|
$$&lt;/p&gt;
&lt;p&gt;曼哈顿距离是两个点在各个维度上的差的绝对值之和&lt;sup id="fnref:17"&gt;&lt;a href="#fn:17" class="footnote-ref" role="doc-noteref"&gt;17&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9d81381e5fb5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;上图中，绿线为欧式距离，红、黄、蓝线为曼哈顿距离。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;闵氏距离(Minkowski distance)&lt;/strong&gt;
 &lt;div id="闵氏距离minkowski-distance" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%97%b5%e6%b0%8f%e8%b7%9d%e7%a6%bbminkowski-distance" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;$$
d(\mathbf a,\mathbf b)= \left( \sum_{i=1}^n | a_i-b_i|^p \right)^{1/p}
$$&lt;/p&gt;
&lt;p&gt;下图表示在闵式距离中取不同的p时，单位长度的点到原点的距离&lt;sup id="fnref:18"&gt;&lt;a href="#fn:18" class="footnote-ref" role="doc-noteref"&gt;18&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/020d3a11e478.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当p=1时，为曼哈顿距离，也写作“L1 distance”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当p=2时，为欧式距离，也写作“L2 distance”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当p=n时，为闵式距离，也写作“Ln distance”&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;余弦相似性（Cosine similarity）&lt;/strong&gt;
 &lt;div id="余弦相似性cosine-similarity" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bd%99%e5%bc%a6%e7%9b%b8%e4%bc%bc%e6%80%a7cosine-similarity" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;即两个向量的夹角的cosine值，也叫余弦值。余弦相似性只跟两个向量的夹角有关系，跟向量的长度无关&lt;sup id="fnref:19"&gt;&lt;a href="#fn:19" class="footnote-ref" role="doc-noteref"&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7c215f476c3e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;两个向量角度越小，余弦相似性越大，值域[-1,1]。cos(0)=1，cos(90)=0，cos(180)=-1。&lt;/p&gt;
&lt;p&gt;两个向量的余弦相似性写作：
$$
cos (\theta)
$$
用向量表示：
$$
cos (\theta)=\frac{\mathbf a\cdot \mathbf b }{||\mathbf a|| , ||\mathbf b||}= \frac{ \sum_{i=1}^n \mathbf a_i \mathbf b_i}{ \sqrt {\sum_{i=1}^n \mathbf a_i ^2} \cdot \sqrt {\sum_{i=1}^n \mathbf b_i ^2}}
$$&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c561d1e0ee46.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;内积（ inner product）&lt;/strong&gt;
 &lt;div id="内积-inner-product" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%86%85%e7%a7%af-inner-product" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;也称为点积（Dot product），可以被用来表示向量的长度和角度。内积等于向量的&lt;em&gt;欧几里得距离&lt;/em&gt;乘以&lt;em&gt;夹角余弦值&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;二维空间中的内积为：
$$
\mathbf a\cdot \mathbf b=||\mathbf a|| , ||\mathbf b||, cos \theta
$$
or
$$
\mathbf a\cdot \mathbf b= a_1 b_1 + a_2 b_2
$$
在n维空间中的内积为（&lt;strong&gt;a&lt;/strong&gt;=[a1,a2,···,an],&lt;strong&gt;b&lt;/strong&gt;=[b1,b2,···,bn]）：
$$
\mathbf a\cdot \mathbf b=\sum_{i=1}^n a_ib_i= a_1b_1 + a_2b_2 + \cdots + a_nb_n
$$&lt;/p&gt;
&lt;p&gt;此时来看下面这个图就能看懂了。用上面的公式也可反推n维向量的距离操作符的含义。&lt;/p&gt;
&lt;p&gt;他们分别是：欧几里得距离，余弦距离，内积&lt;sup id="fnref:20"&gt;&lt;a href="#fn:20" class="footnote-ref" role="doc-noteref"&gt;20&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8b206ce5a7c9.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;他们都可以描述两个向量的相似性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;欧几里得距离仅包含两个向量的距离信息&lt;/li&gt;
&lt;li&gt;余弦距离：仅包含两个向量的角度信息&lt;/li&gt;
&lt;li&gt;内积：既包含距离信息，也包含角度信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然还有更多数学模型上的向量相似性计算方法，不过要看向量数据库支不支持。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;jaccard距离&lt;/strong&gt;
 &lt;div id="jaccard距离" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jaccard%e8%b7%9d%e7%a6%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;简而言之，交集除以并集&lt;sup id="fnref:21"&gt;&lt;a href="#fn:21" class="footnote-ref" role="doc-noteref"&gt;21&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e5680f0330ab.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;用公式表达：
$$
J(A,B)= \frac{|A\cap B| }{|A \cup B|}
$$&lt;/p&gt;
&lt;p&gt;用向量表达，即计算两个相等元素个数和不相等元素个数的比&lt;sup id="fnref:22"&gt;&lt;a href="#fn:22" class="footnote-ref" role="doc-noteref"&gt;22&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ee60ca0304e3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;Hamming距离&lt;/strong&gt;
 &lt;div id="hamming距离" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hamming%e8%b7%9d%e7%a6%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;两个相同长度的字符串或向量在各自位置上的不同数量&lt;sup id="fnref:23"&gt;&lt;a href="#fn:23" class="footnote-ref" role="doc-noteref"&gt;23&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;ka&lt;strong&gt;rol&lt;/strong&gt;in&amp;rdquo; and &amp;ldquo;ka&lt;strong&gt;thr&lt;/strong&gt;in&amp;rdquo; is 3.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;k&lt;strong&gt;a&lt;/strong&gt;r&lt;strong&gt;ol&lt;/strong&gt;in&amp;rdquo; and &amp;ldquo;k&lt;strong&gt;e&lt;/strong&gt;r&lt;strong&gt;st&lt;/strong&gt;in&amp;rdquo; is 3.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;k&lt;strong&gt;athr&lt;/strong&gt;in&amp;rdquo; and &amp;ldquo;k&lt;strong&gt;erst&lt;/strong&gt;in&amp;rdquo; is 4.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0000&lt;/strong&gt; and &lt;strong&gt;1111&lt;/strong&gt; is 4.&lt;/li&gt;
&lt;li&gt;2&lt;strong&gt;17&lt;/strong&gt;3&lt;strong&gt;8&lt;/strong&gt;96 and 2&lt;strong&gt;23&lt;/strong&gt;3&lt;strong&gt;7&lt;/strong&gt;96 is 3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;图例&lt;sup id="fnref:24"&gt;&lt;a href="#fn:24" class="footnote-ref" role="doc-noteref"&gt;24&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2df7e926cb52.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;Delaunay三角剖分&lt;/strong&gt;
 &lt;div id="delaunay三角剖分" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#delaunay%e4%b8%89%e8%a7%92%e5%89%96%e5%88%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Delaunay三角剖分是对平面上一组点集进行的操作，它将这些点集的凸包（包含多个点）细分为多个三角形，这些三角形的外接圆不包含任何点集中的点。这样做最大化了所有三角形中最小角的大小，并倾向于避免产生细长的三角形&lt;sup id="fnref:25"&gt;&lt;a href="#fn:25" class="footnote-ref" role="doc-noteref"&gt;25&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;不满足 三角形的外接圆不包含任何点集中的点：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/61a1cd01f71f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;满足 三角形的外接圆不包含任何点集中的点：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/dfbb3c28e6e3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;例如剖分一下点集：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b5d7da74a98a.png" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;合理的剖分：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b13e838ade76.png" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;Delaunay三角剖分其实并不是一种算法，它只是给出了一个“好的”三角网格的定义，它的优秀特性是空圆特性和最大化最小角特性，这两个特性避免了狭长三角形的产生，也使得Delaunay三角剖分应用广泛。&lt;/p&gt;

&lt;h4 class="relative group"&gt;&lt;strong&gt;voronoi diagram&lt;/strong&gt;
 &lt;div id="voronoi-diagram" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#voronoi-diagram" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Delaunay三角剖分（Delaunay triangulation）是一个在一般位置中的离散点集P的三角剖分，它对应于P的Voronoi图的对偶图。Delaunay三角形的外接圆心是Voronoi图的顶点。在二维情况下，Voronoi的顶点通过边连接，这些边可以通过Delaunay三角形的邻接关系得出：如果两个三角形在德劳内剖分中共享一条边，那么它们的外接圆心在Voronoi镶嵌中应该用一条边连接起来&lt;sup id="fnref:26"&gt;&lt;a href="#fn:26" class="footnote-ref" role="doc-noteref"&gt;26&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ea403a88c609.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;Voronoi图的主要特性是：&lt;em&gt;从一个质心到其区域内任何点的距离都小于该点到另一个质心的距离&lt;/em&gt;。
$$
R_k={x \in X ,|,d(x,P_k) \le d(x,P_j) ; \mathrm{for ,all },j \neq k}
$$
Rk是质心，d(x,Pk)是质心到其区域内任何点的距离，d(x,Pj)是其他质心到该区域任何点的距离。&lt;/p&gt;
&lt;p&gt;由于d距离计算方式的不同，Voronoi图还可以有不同的样貌&lt;sup id="fnref:27"&gt;&lt;a href="#fn:27" class="footnote-ref" role="doc-noteref"&gt;27&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d7f64ffda7c7.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;向量数据库的索引
 &lt;div id="向量数据库的索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;邻近搜索
 &lt;div id="邻近搜索" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%82%bb%e8%bf%91%e6%90%9c%e7%b4%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ENN（exact nearest neighbor）：指的是在给定数据集中找到与查询点最接近的点或向量。这种方法保证了最高的精确度，但随着数据集的规模增大，计算成本会急剧升高，因为它需要评估查询点与数据集中每个点之间的距离。&lt;/p&gt;
&lt;p&gt;ANN（Approximate nearest neighbor）：为了提高效率，在牺牲一定的精确度条件下，近似的找到与查询点最近的点。这种方法通过各种算法实现，可以大大降低计算成本，特别是在处理大规模数据集时更为有效。&lt;/p&gt;
&lt;p&gt;KNN (K-Nearest Neighbors): 这是一种常用的机器学习算法，工作原理是找到数据集中距离给定查询点最近的K个邻居&lt;/p&gt;

&lt;h3 class="relative group"&gt;索引评价标准
 &lt;div id="索引评价标准" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%b4%a2%e5%bc%95%e8%af%84%e4%bb%b7%e6%a0%87%e5%87%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;评价一个索引的好坏总是依赖于具体的数据模型的，总体来说包含如下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询时间。查询的速度是非常关键的，在大模型中尤为重视。&lt;/li&gt;
&lt;li&gt;查询质量。ANN查询不会总是返回最精准的结果，但查询质量也不能偏差过大，而查询质量也有很多指标，其中包括最常用的召回率。&lt;/li&gt;
&lt;li&gt;内存消耗。查询索引所消耗的内存，在内存上查找明显比在磁盘上查找更快。&lt;/li&gt;
&lt;li&gt;训练时间。有些查询方法需要训练才能达到较好的状态。&lt;/li&gt;
&lt;li&gt;写入时间。写入向量时对索引的影响，以及包含所有维护。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中大部分指标都比较好理解，这里主要讲解&lt;em&gt;查询质量&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;ANN查询中，不会总是返回精确的结果。搜索一个元素集时，包括：查询的范围（retrieved elements）、所有正确元素集（relevant elements）、返回的正确元素集（true postives）、返回的错误元素集（false positives）&lt;sup id="fnref:28"&gt;&lt;a href="#fn:28" class="footnote-ref" role="doc-noteref"&gt;28&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7712556dface.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;TP = True positive; FP = False positive; TN = True negative; FN = False negative&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;准确率（Accuracy）&lt;/strong&gt;：
$$
Accuracy=\frac{TP+TN}{TP+FP+TN+FN}
$$
或写成：
$$
Accuracy=\frac{所有正确的元素}{所有元素}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;精确率（Precision）&lt;/strong&gt;：
$$
Precision=\frac{TP}{TP+FP}
$$&lt;/p&gt;
&lt;p&gt;或写成：
$$
Precision=\frac{检索出的正确元素}{检索出的所有元素}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;召回率(Recall)&lt;/strong&gt;：
$$
Recall=\frac{TP}{TP+FN}
$$
或写成：
$$
Recall=\frac{检索出的正确元素}{所有正确的元素}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;F-值（F-measure）&lt;/strong&gt;：相当于加权后的精确率和召回率
$$
Recall=2 \cdot \frac{precision \cdot recall}{precision+recall}
$$&lt;/p&gt;
&lt;p&gt;示例：考虑一个用来识别数字照片中的狗（和相关元素）的计算机程序。在处理一张包含十只猫和十二只狗的照片时，程序识别出了八只狗。在被识别为狗的八个元素中，只有五个实际上是狗（true positives），而其他三个是猫（false positives）。有七只狗被漏识别（false negatives），七只猫被正确排除（true negatives）。那么该程序的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;准确率=12/(10+12)（跟识别程序本身关系不大）&lt;/li&gt;
&lt;li&gt;精确率=5/8（true positives/检索出的所有元素）&lt;/li&gt;
&lt;li&gt;召回率=5/12（true positives/所有正确元素）&lt;/li&gt;
&lt;li&gt;F值=2*[(5/18)*(5/12)]/[(5/18)+(5/12)]&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;locality-sensitive hashing (LSH)
 &lt;div id="locality-sensitive-hashing-lsh" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#locality-sensitive-hashing-lsh" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LSH是一种用于通过将数据向量转换为哈希值来缩小搜索范围的方法，同时保留它们相似性的信息。&lt;/p&gt;

&lt;h4 class="relative group"&gt;LSH的构建
 &lt;div id="lsh的构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lsh%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;LSH有许多实现方式，这里介绍比较传统的实现。这个传统LSH的实现包含3个部分&lt;sup id="fnref1:22"&gt;&lt;a href="#fn:22" class="footnote-ref" role="doc-noteref"&gt;22&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Shingling：将原始文本编码为向量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MinHashing：将向量转换为一种称为signature的特殊表示形式，用于比较它们之间的相似性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LSH function：将signature哈希到不同的桶中。如果一对向量的signature至少有一次落入同一个桶中，它们就被认为是候选者。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 class="relative group"&gt;Shingling
 &lt;div id="shingling" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shingling" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;shingling是一种embedding方式（个人观点）。Shingling将自然语言识别成k个连续的token，重复的token将被剔除&lt;sup id="fnref2:22"&gt;&lt;a href="#fn:22" class="footnote-ref" role="doc-noteref"&gt;22&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/45d8beeaced2.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;此时我们有了基于k-gram的token集，接下来就是转化为向量。&lt;/p&gt;
&lt;p&gt;首先有一个全“0”向量，向量长度等于token集的长度。每个token所对应的向量的位置设置为1：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/288f0f1f9f2c.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;最终的结果就是，我们得到一个很长的向量，向量只有0、1元素，向量信息包含一条语句的语义。&lt;/p&gt;

&lt;h4 class="relative group"&gt;MinHashing
 &lt;div id="minhashing" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#minhashing" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;由于向量维度实在太高，直接通过one-hot encoding出来的向量来计算近似距离的效果非常差。我们需要将稀疏向量转化为密集向量，这个过程在LSH中称为MinHashing ，转化后的向量称为MinHashing signature。&lt;/p&gt;
&lt;p&gt;MinHashing在初学者最初认识它的时候会有点难理解，认识了以后你会发现它很简单。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;MinHashing is a hash function that permutes the components of an input vector and then returns the first index where the permutated vector component equals 1.&lt;/p&gt;
&lt;/blockquote&gt;&lt;ol&gt;
&lt;li&gt;首先打乱排序（permutation），将一个向量的元素重新排列&lt;/li&gt;
&lt;li&gt;返回排序后的向量的第一个1元素的index&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;例如以下例子：&lt;/p&gt;
&lt;p&gt;u1向量(0,0,1,1,0)，第一次随机换行后，对应index是0，第二次随机换行后，对应的index是0&lt;sup id="fnref:29"&gt;&lt;a href="#fn:29" class="footnote-ref" role="doc-noteref"&gt;29&lt;/a&gt;&lt;/sup&gt;，u1经过minhashing后的signature为(0,0)。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c5997f710719.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;实际上可以使用多个 minhash 值来近似求得向量之间的 Jaccard 相似度。实际上，使用的 minhash 值越多，近似就越准确。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9c95377842ce.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;LSH function
 &lt;div id="lsh-function" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lsh-function" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;即使我们将稀疏向量转化为了密集向量，但是密集向量的维度也会很高，直接检索的效率很低。&lt;/p&gt;
&lt;p&gt;我们可以通过hash表来提升查询效率。但是要注意，如果直接用随机的hash算法容易将邻近的向量放在不同的hash桶中，我们应该找一个能将邻近的向量应该放在同一个hash桶中的hash算法，这就是LSH——局部敏感HASH算法。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;LSH mechanism builds a hash table consisting of several parts which puts a pair of signatures into the same bucket if they have at least one corresponding part.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;局部敏感hash算法的理念也很简单，将signature分片，分片后的子signature各自计算hash值，子hash值碰撞的列为candidate。&lt;/p&gt;
&lt;p&gt;以下例子比较容易理解自行阅读：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f95a92163fc8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;从极限角度思考，b=1就是不分片直接hash，完全没有发挥LSH的效果；b=signature的元素个数，每个元素一个分片，也就是每个元素一个hash值，可以做到比较精确的近似比较，但是对计算量和内存是极大的负担。&lt;/p&gt;

&lt;h4 class="relative group"&gt;LSH参数与错误率
 &lt;div id="lsh参数与错误率" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lsh%e5%8f%82%e6%95%b0%e4%b8%8e%e9%94%99%e8%af%af%e7%8e%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;一个向量的candidate向量概率直接影响召回率。candidate向量的概率如下，其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;s代表近似度&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;b代表分片数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;r代表每个分片中的行数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/11d2d0ff3d63.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;如果将P和s作为对比坐标，根据公式，其向量相似度和candidate概率关系如下：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d9a7f7f7c269.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5ce91d839ace.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;分区个数b越大，candidate相似概率越小。&lt;/p&gt;
&lt;p&gt;同时，调整b和s会影响P，P的值与FP、TN又有关系。&lt;/p&gt;
&lt;p&gt;例如返回更多的candidates，这自然会导致更多的false postive——即返回不相似的“candidate pair”。这是修改参数 b 的不可避免的结果。&lt;/p&gt;
&lt;p&gt;TP = True positive; FP = False positive; TN = True negative; FN = False negative&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/888c9b18576f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;LSH 容易受到高维数据的影响：更多的维度需要更长的signature长度和更多的计算才能保持良好的搜索质量。在这种情况下，建议使用其他索引。&lt;/p&gt;

&lt;h4 class="relative group"&gt;more
 &lt;div id="more" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#more" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;还有两篇没啃完，大概看了下跟binary vector和欧几里得距离相关&lt;/p&gt;
&lt;p&gt;&lt;a href="https://towardsdatascience.com/similarity-search-part-6-random-projections-with-lsh-forest-f2e9b31dcc47" target="_blank" rel="noreferrer"&gt;https://towardsdatascience.com/similarity-search-part-6-random-projections-with-lsh-forest-f2e9b31dcc47&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://towardsdatascience.com/similarity-search-part-7-lsh-compositions-1b2ae8239aca" target="_blank" rel="noreferrer"&gt;https://towardsdatascience.com/similarity-search-part-7-lsh-compositions-1b2ae8239aca&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;HNSW索引
 &lt;div id="hnsw索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;HNSW算法（ Hierarchical navigable small world）是基于多图层的邻近算法。HNSW目前是最流行的向量索引算法之一。&lt;/p&gt;
&lt;p&gt;从高层次来看，HNSW基于&lt;a href="https://en.wikipedia.org/wiki/Small-world_network" target="_blank" rel="noreferrer"&gt;小世界理论&lt;/a&gt;。小世界理论最初源于社会心理学的&lt;a href="https://en.wikipedia.org/wiki/Six_degrees_of_separation" target="_blank" rel="noreferrer"&gt;六度分隔理论&lt;/a&gt;，任何两个人之间仅仅通过五层社会关系就能够被相互连接，换句话说，就是任何两个地球上的人都可以通过最多六步社会联系来相互联系上。小世界理论后来被实验和使用经验佐证而被广泛接受，并扩展到非社会关系网络中。注意小世界理论是一种现象。&lt;/p&gt;
&lt;p&gt;总之，小世界理论是在说明“&lt;em&gt;两个事务间的联系实际上是很短的&lt;/em&gt;”。HNSW所做的事情就是建立两个元素之间的联系、减少联系数。&lt;/p&gt;

&lt;h4 class="relative group"&gt;HNSW索引的构建
 &lt;div id="hnsw索引的构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e7%b4%a2%e5%bc%95%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;看下HNSW论文关于构建HNSW图层的算法&lt;sup id="fnref:30"&gt;&lt;a href="#fn:30" class="footnote-ref" role="doc-noteref"&gt;30&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/da93d451c90f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;构建算法中有几个要素是比较重要的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;M为新增的边connection，表示新插入的节点的新边个数。&lt;/li&gt;
&lt;li&gt;Mmax为节点的边的最大个数。如果一直插入的是邻近节点，那么已有的邻近节点的边有可能一直增加，查找时会浪费算力。当新增节点时发现新插入边导致已有邻近节点的边大于Mmax，那么需要做shrink connection。&lt;/li&gt;
&lt;li&gt;efConstruction为邻近的节点集。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构建图例&lt;sup id="fnref:31"&gt;&lt;a href="#fn:31" class="footnote-ref" role="doc-noteref"&gt;31&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/79c887052aca.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HNSW添加node的步骤（without shrink connection）&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;新节点插入时，先在最上层通过&lt;em&gt;efConstruction&lt;/em&gt;找到邻近节点。以找到的最邻近节点当做entry point进入到下一层，然后继续通过那层的&lt;em&gt;efConstruction&lt;/em&gt;查找邻近节点。&lt;/li&gt;
&lt;li&gt;在某层（如L=2)做node插入。从&lt;em&gt;efConstruction&lt;/em&gt;中找出M个节点，并连接新节点，此时新增了1个节点并添加M条边与之相连。&lt;/li&gt;
&lt;li&gt;重复step2，直到最底层layer0。&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 class="relative group"&gt;HNSW启发式邻居构建
 &lt;div id="hnsw启发式邻居构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e5%90%af%e5%8f%91%e5%bc%8f%e9%82%bb%e5%b1%85%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;基本的HNSW索引结构构建还存在一个问题，如果有两个簇相隔比较远，那么根据最具备的HNSW构建算法，两个簇几乎不可能相连，因为构建HNSW的基本算法是基于最邻近的节点&lt;em&gt;efConstruction&lt;/em&gt;来构建的。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/1603.09320" target="_blank" rel="noreferrer"&gt;HNSW original paper&lt;/a&gt;除了提出最基本的构建HNSW的算法，也提出了解决孤立群集的启发式算法：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0ccf3de6e6ec.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Fig.2 为两个孤立的群集选择图形邻居的启发式方法。一个新元素被插入到cluster 1的边界上。该元素的所有最近邻居都属于cluster 1，因此错过了群集之间的Delaunay三角网的边缘。然而，启发式方法选择了来自群集2的元素e2，因此，如果插入的元素与来自群集1的任何其他元素相比更靠近e2，就能保持全局连通性。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;“启发式算法不仅考虑了图中节点之间最近的距离，还考虑了图上不同区域之间的连通性”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如下图添加一个X节点，这里就应该启用启发式算法，与cluster A建立连接性，而不是简单的添加到邻近节点上：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b7393a1117ad.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;HNSW索引寻迹
 &lt;div id="hnsw索引寻迹" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e7%b4%a2%e5%bc%95%e5%af%bb%e8%bf%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/1603.09320" target="_blank" rel="noreferrer"&gt;HNSW original paper&lt;/a&gt;中提到的HNSW寻找KNN的方法的主体逻辑包含如下2个算法：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b4bbc841673b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b7ec9e80d0b9.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;算法2看上去要稍微复杂点，实际上逻辑很简单，算法2的功能是在该层中找到对于q最邻近的节点集ef。算法2简单来说就是把candidate节点加入到ef集并比较距离，把最远的节点剔出去，这样返回的W就是该层对于q的ef。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;算法5的功能是返回q的K个最邻近节点，它会调用算法2两次（或多次）。for中的第一行输入参数ef=1，也就是说非最底层的layer都只找最邻近的ep（entry point），最底层（lc=0）返回K个最邻近节点集W。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/3154b27761ee.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;HNSW复杂度
 &lt;div id="hnsw复杂度" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e5%a4%8d%e6%9d%82%e5%ba%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;HNSW的层数为log(N)函数。&lt;/p&gt;
&lt;p&gt;查询复杂度：在Delaunay graph中可以严格评估复杂度，平均复杂度为 O(log(N))（非Delaunay graph，如存在启发式邻近算法的graph，论文没有给出具体的复杂度公式）。&lt;/p&gt;
&lt;p&gt;构建复杂度：HNSW是通过所有元素迭代插入构建的，平均复杂度为O(N∙log(N)) 。&lt;/p&gt;

&lt;h4 class="relative group"&gt;HNSW索引参数
 &lt;div id="hnsw索引参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hnsw%e7%b4%a2%e5%bc%95%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;一般向量数据的HNSW索引都有几个参数可以调整，这些参数会影响索引构建速度、召回率等。不同的数据库参数可能稍微有差异，这里以pgvector的HNSW参数为例：&lt;/p&gt;
&lt;p&gt;索引构建参数：&lt;/p&gt;
&lt;p&gt;• m：向量的边的最大个数，默认为16。相当于论文中Mmax。
• ef_construction：构建索引时邻近列表中的向量个数，默认64。相当于论文中ef_construction。&lt;/p&gt;
&lt;p&gt;索引搜索参数：&lt;/p&gt;
&lt;p&gt;• hnsw.ef_search可调整搜索时邻近列表中的向量个数（也相当于论文中ef_construction）。必须大于等于limit。&lt;/p&gt;
&lt;p&gt;构建索引时，调整ef_construction对创建时间和召回率的影响&lt;sup id="fnref1:20"&gt;&lt;a href="#fn:20" class="footnote-ref" role="doc-noteref"&gt;20&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/44a379598309.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;提高ef_construction这个参数会提高召回率，延长创建索引时间。ef_construction=256以后，索引构建时间明显增加，但召回率提升不明显。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ebd3ed59025b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;提高m，同样会提高召回率，延长创建索引时间。m=36以后，索引构建时间明显增加，但召回率提升不明显。&lt;/p&gt;
&lt;p&gt;同样的，提高hnsw.ef_search会提升召回率，降低性能。&lt;/p&gt;

&lt;h3 class="relative group"&gt;IVFFlat索引
 &lt;div id="ivfflat索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ivfflat%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;IVFFlat索引全称为扁平压缩的倒排索引（ Inverted File with Flat Compression）（跟invert有啥关系？分不了类的索引都叫倒排？）。IVFFlat索引的核心理念基于voronoi diagram：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Voronoi图的主要特性是：&lt;em&gt;从一个质心到其区域内任何点的距离都小于该点到另一个质心的距离&lt;/em&gt;。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;这个特性用公式表达：
$$
R_k={x \in X ,|,d(x,P_k) \le d(x,P_j) ; \mathrm{for ,all },j \neq k}
$$
Rk是质心，d(x,Pk)是质心到其区域内任何点的距离，d(x,Pj)是其他质心到该区域任何点的距离。&lt;/p&gt;
&lt;p&gt;利用这个概念可以通过设置质心，把众多向量进行区域划分，然后利用voronio图的特性，粗略地找到邻近点。&lt;/p&gt;

&lt;h4 class="relative group"&gt;IVFFlat索引的构建
 &lt;div id="ivfflat索引的构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ivfflat%e7%b4%a2%e5%bc%95%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;我们将高维空间下降到2维以便理解IVFFlat索引构建&lt;sup id="fnref:32"&gt;&lt;a href="#fn:32" class="footnote-ref" role="doc-noteref"&gt;32&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;例如以下一堆x表示点（或者叫向量），假设我们有三个质心&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/370e9bbd8bac.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;三个质心划分出3个Voronoi cell，所有点都分配到各自的Voronoi cell中&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8e9e1aed5c5b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;IVFFlat索引寻迹
 &lt;div id="ivfflat索引寻迹" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ivfflat%e7%b4%a2%e5%bc%95%e5%af%bb%e8%bf%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;此时有一个query节点，然后计算它到所有质心的距离，然后找到最近的那个质心，这个质心所在的cell就是接下来要寻找的区域。最后在这个区域范围内，找到邻近的节点&lt;sup id="fnref:33"&gt;&lt;a href="#fn:33" class="footnote-ref" role="doc-noteref"&gt;33&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/bad429ed41be.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;边界问题：&lt;/p&gt;
&lt;p&gt;上面的查询路径存在边界问题。当query靠近区域边界的时候，如果存在最近的节点在其他区域中，那么靠“仅搜索区域内邻近节点”的算法，是不会找到这个最邻近节点的。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9298bd73b504.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;边界问题本质是因为：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;voronio图只能保证某节点到其区域质心的距离小于到其他质心的距离，但不保证某节点到区域内其他节点的距离小于到其他区域节点的距离&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个问题可以通过设置搜索的区域数量来缓解，例如把搜索的区域数量从1增加到3：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9e9493428d53.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;增加搜索区域数量一般都以参数形式设置在数据库中，例如pgvector中的ivfflat.probes。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IVFFlat寻迹概述&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;计算query节点到所有其他质心的距离，找到最近的那个&lt;/li&gt;
&lt;li&gt;根据查询cells个数的入参（例如probes），在top probes个cells中寻找邻近点&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 class="relative group"&gt;IVFFlat索引参数
 &lt;div id="ivfflat索引参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ivfflat%e7%b4%a2%e5%bc%95%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;同样的，支持IVFFlat索引的向量数据库中，一般至少都有list和probe两个参数。这些参数会影响索引搜索性能、召回率。这里以Faiss的参数为例&lt;sup id="fnref1:32"&gt;&lt;a href="#fn:32" class="footnote-ref" role="doc-noteref"&gt;32&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;nlist：构建区域的个数。增大nlist会提高搜索邻近质心的时间，但会减少区域内搜索节点的时间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nprobe：搜索区域的个数。增大nprobe增大搜索区域个数，很明显会降低搜索性能，提升召回率&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;理论上来说，对于nlist，最好针对性的对向量数据的结构、数据库类型进行测试，不一定提高nlist总是会降低响应时间。对于nprobe，增大nprobe一定会降低搜索性能、提升召回率，但是nprobe太大没有意义，不符合ANN的初衷。&lt;/p&gt;
&lt;p&gt;以下源自Pinecone对Faiss IVVFlat索引的性能测试：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5ca487b356dd.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;PQ乘积量化
 &lt;div id="pq乘积量化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pq%e4%b9%98%e7%a7%af%e9%87%8f%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;100w个密集向量可能需要上G的内存，而真实世界中的向量远不止这个数。如果不加以管理，相似性向量搜索可能需要大量内存，然而内存RAM是有限的。向量的大小随向量的维度、向量个数而增加。&lt;/p&gt;
&lt;p&gt;乘积量化（Product Quantization）旨在减少内存使用，还可以提升查询速度（因为计算量减少了）。PQ是一种有损压缩方法，这会导致向量检索的准确性降低，不过这在ANN需求中是行的。&lt;/p&gt;
&lt;p&gt;PQ的算法逻辑稍微比其他算法复杂一些，强烈推荐这篇文章&lt;a href="https://towardsdatascience.com/similarity-search-product-quantization-b2a1a6397701" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 2: Product Quantization&lt;/a&gt;&lt;sup id="fnref:34"&gt;&lt;a href="#fn:34" class="footnote-ref" role="doc-noteref"&gt;34&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;PQ的构建
 &lt;div id="pq的构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pq%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/56b112821338.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;步骤描述：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;subvectors&amp;ndash;将原始的高维向量切分成n个低维子向量&lt;/li&gt;
&lt;li&gt;codebook&amp;ndash;将n个&lt;em&gt;各自&lt;/em&gt;所有的子向量通过k-means算法计算各自的voronoi图（或者其他算法），计算出来有n个不同的voronoi图，这些voronoi图就是codebook（这里假设每个voronoi图都有k个质心）&lt;/li&gt;
&lt;li&gt;clustering&amp;ndash;把n个子向量放进各自已聚类完成的voronoi图中计算出最近质心&lt;/li&gt;
&lt;li&gt;quantized vectors&amp;ndash;将这n个最近质心当做新的向量-量化后向量&lt;/li&gt;
&lt;li&gt;reproduction values&amp;ndash;以n个子空间的各自&lt;em&gt;最近质心的编号&lt;/em&gt;为新值，合起来的新增称为PQ code&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其中5.reproduction values详细描述：&lt;/p&gt;
&lt;p&gt;根据n个子向量和每个子空间的中的k个质心，我们可以得到一个n*k的质心矩阵。取每个子向量的最近质心的编号，就是PQ code。&lt;/p&gt;
&lt;p&gt;（btw：如果严谨一点，下图中所有元素的下角编号应该都是从1开始，而不是0）&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fc2938307d7e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;新的PQ code相当于原向量失真压缩后的新向量（reproduction value），新的距离计算可以直接计算PQ code的L2距离。&lt;/p&gt;

&lt;h4 class="relative group"&gt;PQ的检索
 &lt;div id="pq的检索" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pq%e7%9a%84%e6%a3%80%e7%b4%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;基于PQ original paper&lt;sup id="fnref:35"&gt;&lt;a href="#fn:35" class="footnote-ref" role="doc-noteref"&gt;35&lt;/a&gt;&lt;/sup&gt;，PQ检索方式有两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对称方式：向量x，向量y之间的距离，近似通过他俩的质心q(x),q(y)的距离来代替。换言之，俩个向量的距离可通过两个向量的PQ code距离来代替&lt;/li&gt;
&lt;li&gt;非对称方式：向量x，向量y之间的距离，近似通过x到质心q(y)的距离来替代。换言之，俩个向量的距离可通过查询向量原值和另一个向量的PQ code来计算&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d3704a6f01b5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;很明显两个模式计算的距离准确度是不一样的：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9697622aad6e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;上图表示8个子空间，256个质心，在不同模式下计算两个向量的距离准确度。可以看出非对称模式比对称模式的准确度要高。&lt;/p&gt;
&lt;p&gt;在对比两个向量距离的时候，对称和非对称模式的距离计算模型是比较有用的。但在查找PQ近似向量的时候场景中，稍微有些差别，特别是对称模式计算失真会非常严重：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对称方式的查询速度是非常快的，因为code table已经通过PQ构建过程计算并保留了，只需要先通过code table把查询向量x的PQ code算出来（计算量极小），然后通过PQ code反向获得的code table中对应的那些子code table，这个子code table里的向量都是与其距离相等的近似向量。这种方式计算量极少，直接查表即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对称方式的失真情况相对比较严重（上面2个图还不是很好，把它想象成一个cell中包含多个向量的voronoi图，就知道对称方式失真有多严重了），非对称方式可以&lt;em&gt;稍微&lt;/em&gt;缓解这个问题。非对称方式先计算向量x的PQ code，然后同样通过PQ code反向获得的code table中对应的那些子code table，然后通过向量x与这个子code table中的向量进行距离计算，得到KNN。它的计算量为n*km（n=子空间数，km≈所有向量数/质心数）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/25945e785366.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;非对称的需要通过PQ code找到质心，在质心所在的子空间中找KNN，查询向量x与已存在向量y的距离通过向量x与y的质心来近似替代。&lt;/p&gt;
&lt;p&gt;PQ非对称方式检索&lt;sup id="fnref1:34"&gt;&lt;a href="#fn:34" class="footnote-ref" role="doc-noteref"&gt;34&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ba66cc8da1b9.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f08ffd4fc669.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;PQ非对称方式检索步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查询向量分成为多个子向量&lt;/li&gt;
&lt;li&gt;计算子向量和质心矩阵的距离&lt;/li&gt;
&lt;li&gt;取子空间中最近的质心，当做查询向量的PQ code&lt;/li&gt;
&lt;li&gt;通过查询向量和PQ code对应的质心来计算近似距离，距离可在各自子空间单独计算然后累加&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们前面提到非对称相对对称的近似距离计算要稍微好些，在某些场景下非对称的距离跟实际距离也可能产生较大的差距：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6213fe57a4fc.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;以上图比较好理解。在同一cell中，最远端的vector跟最靠近质心的vector跟质心的距离可能差别较大，只计算到质心距离的partial distance无法体现这种差别。&lt;/p&gt;

&lt;h4 class="relative group"&gt;PQ的参数及其影响
 &lt;div id="pq的参数及其影响" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pq%e7%9a%84%e5%8f%82%e6%95%b0%e5%8f%8a%e5%85%b6%e5%bd%b1%e5%93%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;PQ至少有两个参数对性能和内存影响是比较大的，分别是子空间数m，子空间的质心数k。&lt;/p&gt;
&lt;p&gt;召回率：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The product quantizer is parametrized by the number of subvectors m and the number of quantizers per subvector k ∗ , producing a code of length m × log2 k&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;子空间有m个，每个子空间的质心数是k^* 个，产生一个PQ code的长度（bits单位）为&lt;sup id="fnref1:35"&gt;&lt;a href="#fn:35" class="footnote-ref" role="doc-noteref"&gt;35&lt;/a&gt;&lt;/sup&gt;：
$$
code ; length , (bits)=m \cdot \log_2 k^*
$$&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c89aa21160f6.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;子空间m越多，召回率越高；PQ code越长，召回率也越高。PQ code越长其实就是质心数越多。注意这里的具体值是基于论文的数据集的。&lt;/p&gt;
&lt;p&gt;内存和复杂度：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/06d80385f539.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;k代表聚类质心数，D代表维度，m代表子空间数。k*代表子空间中的质心，D*代表子空间中的维度。&lt;/p&gt;
&lt;p&gt;例如k=2048，D=128，m=8，复杂度如下&lt;sup id="fnref:36"&gt;&lt;a href="#fn:36" class="footnote-ref" role="doc-noteref"&gt;36&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;Operation&lt;/th&gt;
 &lt;th style="text-align: center"&gt;Memory and complexity&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;k-means&lt;/td&gt;
 &lt;td style="text-align: center"&gt;kD = 2048×128 = 262144&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;PQ&lt;/td&gt;
 &lt;td style="text-align: center"&gt;mk&lt;em&gt;D&lt;/em&gt; = (k^(1/m))×D = (2048^(1/8))×128 = 332&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以看到PQ在搜索时复杂度明显的下降。&lt;/p&gt;

&lt;h3 class="relative group"&gt;DiskAnn&amp;amp;Vamana
 &lt;div id="diskannvamana" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#diskannvamana" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://suhasjs.github.io/files/diskann_neurips19.pdf" target="_blank" rel="noreferrer"&gt;DiskAnn original paper&lt;/a&gt; 的Abstract&lt;sup id="fnref:37"&gt;&lt;a href="#fn:37" class="footnote-ref" role="doc-noteref"&gt;37&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Current state-of-the-art approximate nearest neighbor search (ANNS) algorithms generate indices that must be stored in main memory for fast high-recall search. This makes them expensive and limits the size of the dataset. We present a new graph-based indexing and search system called DiskANN that can index, store, and search a billion point database on a single workstation with just 64GB RAM and an inexpensive solid-state drive (SSD).&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;当前（论文发布于2019年）的ANN算法为了高召回率和性能都依赖RAM。这种方式不仅昂贵而且限制了数据集的大小。DiskANN只需要64GB RAM和不算贵的SSD。&lt;/p&gt;

&lt;h4 class="relative group"&gt;vamana的构建
 &lt;div id="vamana的构建" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vamana%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Vamana 迭代构建一个有向图，首先从一个随机图开始，其中每个节点代表向量空间中的一个数据点。起初，图是高度连接的，所有节点都彼此相连。然后使用一个目标函数对图进行优化，该目标函数旨在最大化最接近节点之间的连接性。这通过修剪大多数随机短程边，同时添加某些长程边来实现，这些长程边连接相距较远的节点（以加速图中的遍历）&lt;sup id="fnref1:37"&gt;&lt;a href="#fn:37" class="footnote-ref" role="doc-noteref"&gt;37&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/29f57b420d43.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;图中有200个二维点并进行了两次迭代。第一次迭代极大的修剪了边，但也把减少路径长度的长边修剪了；当调大阿尔法放开修剪条件时，长边会被增加回来&lt;sup id="fnref:38"&gt;&lt;a href="#fn:38" class="footnote-ref" role="doc-noteref"&gt;38&lt;/a&gt;&lt;/sup&gt;。具体算法参考论文了，大致是这个意思。&lt;/p&gt;

&lt;h4 class="relative group"&gt;DiskAnn的算法
 &lt;div id="diskann的算法" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#diskann%e7%9a%84%e7%ae%97%e6%b3%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;论文的The DiskANN Index Design:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The high-level idea is simple: run Vamana on a dataset P and store the resulting graph on an SSD. At search time, whenever Algorithm 1 requires the out-neighbors of a point p, we simply fetch this information from the SSD. However, note that just storing the vector data for a billion points in 100 dimensions would far exceed the RAM on a workstation! This raises two questions: how do we build a graph over a billion points, and how do we do distance comparisons between the query point and points in our candidate list at search time in Algorithm 1, if we cannot even store the vector data?&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;在向量集合上运行vamana并存储在SSD上。在数据集非常大时，需要面临两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;如何在有限的内存资源下索引如此大规模的数据集？&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;k-means和vamana叠加算法&lt;/strong&gt;：首先，使用 k-means 将数据分成 k 个簇，然后将每个点分配到最近的 i 个簇。通常，i 的数值为 2 就足够了。为每个簇构建基于内存的 Vamana 索引，最后将 k 个 Vamana 索引合并为一个&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;em&gt;如果原始数据不能加载到内存中，搜索时如何计算距离？&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用压缩向量（例如PQ）并将压缩向量存储在主存中。&lt;/p&gt;
&lt;p&gt;如果将索引数据存储在 SSD 上，必须尽量减少磁盘访问次数和磁盘读写请求，以确保搜索延迟较低；同时失真的压缩会降低召回率。因此，DiskANN论文提出了三个优化策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Beam Search&lt;/strong&gt;：简单来说，就是预加载邻居信息。在搜索点 p 时，如果 p 的邻居点不在内存中，则需要从磁盘加载。由于少量 SSD 随机访问操作所需的时间与一次 SSD 单扇区访问操作所需的时间大致相同，可以一次性加载 W 个未访问点的邻居信息。W 的设置不能太大也不能太小。W 设置过大会浪费计算资源和 SSD 带宽，而设置过小则会增加搜索延迟。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Caching Frequently Visited Vertices&lt;/strong&gt;：旨在减少磁盘访问次数。在内存中缓存从起始点出发 C 个跳点范围内的所有点。C 的值最好设置在 3 到 4 之间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implicit Re-Ranking Using Full-Precision Vectors&lt;/strong&gt;：因为PQ是失真压缩，基于PQ的距离算法只是邻近实际距离。为了消除这个差异，我们存储每个点到其邻近的所有距离，这个就是full-precision。至于实现原理，简单来说，也是利用了磁盘的加载效率问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;依据论文，DiskANN的执行效率和召回率好于IVF和HNSW：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e293f1c74241.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;References
 &lt;div id="references" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#references" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/2304.13712" target="_blank" rel="noreferrer"&gt;Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond&lt;/a&gt;&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;劉智皓 (Chih-Hao Liu) &lt;a href="https://tomohiroliu22.medium.com/66%E5%80%8B%E5%A4%A7%E5%9E%8B%E8%AA%9E%E8%A8%80%E6%A8%A1%E5%9E%8Bllm%E7%B6%93%E5%85%B8%E8%AB%96%E6%96%87-0fcdab74e822" target="_blank" rel="noreferrer"&gt;66個大型語言模型LLM經典論文&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/2303.18223.pdf" target="_blank" rel="noreferrer"&gt;A Survey of Large Language Models&lt;/a&gt;&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;a href="https://juejin.cn/post/7346233811212386345" target="_blank" rel="noreferrer"&gt;一文讲清楚，AI、AGI、AIGC与AIGC、NLP、LLM，ChatGPT等概念&lt;/a&gt;&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Prompt_engineering" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Prompt_engineering&lt;/a&gt;&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/2005.11401" target="_blank" rel="noreferrer"&gt; RAG原始论文 &lt;/a&gt;&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;Jonathan Katz pgconfdev2024&lt;a href="https://www.pgevents.ca/events/pgconfdev2024/sessions/session/1/slides/42/pgconfdev-2024-vectors.pdf" target="_blank" rel="noreferrer"&gt;Vectors: How to better support a nasty data type&lt;/a&gt;&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;OpenAI推荐使用vector database &lt;a href="https://openai.com/index/chatgpt-plugins/" target="_blank" rel="noreferrer"&gt;https://openai.com/index/chatgpt-plugins/&lt;/a&gt;&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;&lt;a href="https://thedataquarry.com/posts/vector-db-1/" target="_blank" rel="noreferrer"&gt;Vector databases (1): What makes each one different?&lt;/a&gt;&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;&lt;a href="https://github.com/erikbern/ann-benchmarks" target="_blank" rel="noreferrer"&gt;向量数据库性能对比&lt;/a&gt;&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:11"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics)&lt;/a&gt;&amp;#160;&lt;a href="#fnref:11" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:12"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Unit_vector" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Unit_vector&lt;/a&gt;&amp;#160;&lt;a href="#fnref:12" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:13"&gt;
&lt;p&gt;OpenAI解释单位向量的使用 &lt;a href="https://platform.openai.com/docs/guides/embeddings/frequently-asked-questions" target="_blank" rel="noreferrer"&gt;https://platform.openai.com/docs/guides/embeddings/frequently-asked-questions&lt;/a&gt;&amp;#160;&lt;a href="#fnref:13" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:14"&gt;
&lt;p&gt;Pinecone Natural Language Processing for Semantic Search &lt;a href="https://www.pinecone.io/learn/series/nlp/dense-vector-embeddings-nlp/" target="_blank" rel="noreferrer"&gt;https://www.pinecone.io/learn/series/nlp/dense-vector-embeddings-nlp/&lt;/a&gt;&amp;#160;&lt;a href="#fnref:14" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:15"&gt;
&lt;p&gt;姚远 &lt;a href="https://zhuanlan.zhihu.com/p/684643954" target="_blank" rel="noreferrer"&gt;漫谈数学中的各种空间&lt;/a&gt;&amp;#160;&lt;a href="#fnref:15" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:16"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Euclidean_distance" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Euclidean_distance&lt;/a&gt;&amp;#160;&lt;a href="#fnref:16" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:17"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Taxicab_geometry" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Taxicab_geometry&lt;/a&gt;&amp;#160;&lt;a href="#fnref:17" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:18"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Minkowski_distance" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Minkowski_distance&lt;/a&gt;&amp;#160;&lt;a href="#fnref:18" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:19"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Sine_and_cosine" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Sine_and_cosine&lt;/a&gt;&amp;#160;&lt;a href="#fnref:19" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:20"&gt;
&lt;p&gt;Jonathan Katz pgconfeu2023 &lt;a href="https://www.postgresql.eu/events/pgconfeu2023/sessions/session/4592/slides/435/pgconfeu2023_vectors.pdf" target="_blank" rel="noreferrer"&gt;Vectors are the new JSON&lt;/a&gt;&amp;#160;&lt;a href="#fnref:20" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:20" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:21"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Jaccard_index" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Jaccard_index&lt;/a&gt;&amp;#160;&lt;a href="#fnref:21" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:22"&gt;
&lt;p&gt;Vyacheslav Efimov &lt;a href="https://towardsdatascience.com/similarity-search-part-5-locality-sensitive-hashing-lsh-76ae4b388203" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 5: Locality Sensitive Hashing (LSH)&lt;/a&gt;&amp;#160;&lt;a href="#fnref:22" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:22" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref2:22" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:23"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Hamming_distance" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Hamming_distance&lt;/a&gt;&amp;#160;&lt;a href="#fnref:23" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:24"&gt;
&lt;p&gt;Vyacheslav Efimov &lt;a href="https://towardsdatascience.com/similarity-search-part-6-random-projections-with-lsh-forest-f2e9b31dcc47" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 6: Random Projections with LSH Fores&lt;/a&gt; ↩&amp;#160;&lt;a href="#fnref:24" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:25"&gt;
&lt;p&gt;earthwjl &lt;a href="https://www.jianshu.com/p/172749e6116a" target="_blank" rel="noreferrer"&gt;Delaunay三角剖分学习笔记&lt;/a&gt;&amp;#160;&lt;a href="#fnref:25" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:26"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Delaunay_triangulation" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Delaunay_triangulation&lt;/a&gt;&amp;#160;&lt;a href="#fnref:26" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:27"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Voronoi_diagram" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Voronoi_diagram&lt;/a&gt;&amp;#160;&lt;a href="#fnref:27" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:28"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Precision_and_recall" target="_blank" rel="noreferrer"&gt;https://en.wikipedia.org/wiki/Precision_and_recall&lt;/a&gt;&amp;#160;&lt;a href="#fnref:28" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:29"&gt;
&lt;p&gt;简书 &lt;a href="https://www.jianshu.com/p/d4368c8f40cb" target="_blank" rel="noreferrer"&gt;LSH（局部敏感哈希）算法&lt;/a&gt;&amp;#160;&lt;a href="#fnref:29" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:30"&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/pdf/1603.09320" target="_blank" rel="noreferrer"&gt;HNSW原始论文&lt;/a&gt;&amp;#160;&lt;a href="#fnref:30" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:31"&gt;
&lt;p&gt;Vyacheslav Efimov &lt;a href="https://towardsdatascience.com/similarity-search-part-4-hierarchical-navigable-small-world-hnsw-2aad4fe87d37" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 4: Hierarchical Navigable Small World (HNSW)&lt;/a&gt;&amp;#160;&lt;a href="#fnref:31" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:32"&gt;
&lt;p&gt;&lt;a href="https://www.pinecone.io/learn/series/faiss/vector-indexes/" target="_blank" rel="noreferrer"&gt;https://www.pinecone.io/learn/series/faiss/vector-indexes/&lt;/a&gt;&amp;#160;&lt;a href="#fnref:32" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:32" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:33"&gt;
&lt;p&gt;Vyacheslav Efimov &lt;a href="https://towardsdatascience.com/similarity-search-knn-inverted-file-index-7cab80cc0e79" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 1: kNN &amp;amp; Inverted File Index&lt;/a&gt;&amp;#160;&lt;a href="#fnref:33" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:34"&gt;
&lt;p&gt;Vyacheslav Efimov &lt;a href="https://towardsdatascience.com/similarity-search-product-quantization-b2a1a6397701" target="_blank" rel="noreferrer"&gt;Similarity Search, Part 2: Product Quantization&lt;/a&gt;&amp;#160;&lt;a href="#fnref:34" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:34" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:35"&gt;
&lt;p&gt;&lt;a href="https://inria.hal.science/file/index/docid/514462/filename/paper_hal.pdf" target="_blank" rel="noreferrer"&gt;PQ原始论文&lt;/a&gt;&amp;#160;&lt;a href="#fnref:35" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:35" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:36"&gt;
&lt;p&gt;Pinecone Faiss Manual &lt;a href="https://www.pinecone.io/learn/series/faiss/product-quantization/" target="_blank" rel="noreferrer"&gt;https://www.pinecone.io/learn/series/faiss/product-quantization/&lt;/a&gt;&amp;#160;&lt;a href="#fnref:36" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:37"&gt;
&lt;p&gt;&lt;a href="https://suhasjs.github.io/files/diskann_neurips19.pdf" target="_blank" rel="noreferrer"&gt;DiskANN原始论文&lt;/a&gt;&amp;#160;&lt;a href="#fnref:37" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href="#fnref1:37" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:38"&gt;
&lt;p&gt;DiskANN, A Disk-based ANNS Solution with High Recall and High QPS on Billion-scale Dataset &lt;a href="https://milvus.io/blog/2021-09-24-diskann.md" target="_blank" rel="noreferrer"&gt;https://milvus.io/blog/2021-09-24-diskann.md&lt;/a&gt;&amp;#160;&lt;a href="#fnref:38" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item></channel></rss>