<?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>最后的DBA</title><link>https://lastdba.com/</link><description>Recent content 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/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>一个 DBA 视角看 0526 安可数据库名单</title><link>https://lastdba.com/2026/05/29/%E4%B8%80%E4%B8%AA-dba-%E8%A7%86%E8%A7%92%E7%9C%8B-0526-%E5%AE%89%E5%8F%AF%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8D%E5%8D%95/</link><pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/05/29/%E4%B8%80%E4%B8%AA-dba-%E8%A7%86%E8%A7%92%E7%9C%8B-0526-%E5%AE%89%E5%8F%AF%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8D%E5%8D%95/</guid><description>&lt;blockquote&gt;&lt;p&gt;AI率 5%&lt;/p&gt;
&lt;/blockquote&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%a4%aa%e9%95%bf%e4%b8%8d%e7%9c%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;5 月 26 日，信创数据库名单 2026 年第 2 号发布，23 款产品通过（8 集中式 + 15 分布式），为历次最多。最值得关注：平安、银联、移动、电信四家大甲方各自孵化的数据库首次入围。信创逻辑变了——甲方不再只是买方的角色。&lt;/p&gt;</description><content:encoded>&lt;blockquote&gt;&lt;p&gt;AI率 5%&lt;/p&gt;
&lt;/blockquote&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%a4%aa%e9%95%bf%e4%b8%8d%e7%9c%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;5 月 26 日，信创数据库名单 2026 年第 2 号发布，23 款产品通过（8 集中式 + 15 分布式），为历次最多。最值得关注：平安、银联、移动、电信四家大甲方各自孵化的数据库首次入围。信创逻辑变了——甲方不再只是买方的角色。&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%9c%80%e6%96%b0%e5%90%8d%e5%8d%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;信创数据库名单历次批次统计。数据来源：中国信息安全测评中心 itsec.gov.cn，共 8 批，4 批含数据库。&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;2023#1&lt;/td&gt;
 &lt;td&gt;2023-12-26&lt;/td&gt;
 &lt;td&gt;11（集中式）&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2024#2&lt;/td&gt;
 &lt;td&gt;2024-09-30&lt;/td&gt;
 &lt;td&gt;17（集中式6+分布式11）&lt;/td&gt;
 &lt;td&gt;GaussDB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2025#2&lt;/td&gt;
 &lt;td&gt;2025-08-22&lt;/td&gt;
 &lt;td&gt;3（集中式）&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2026#2&lt;/td&gt;
 &lt;td&gt;2026-05-26&lt;/td&gt;
 &lt;td&gt;23（集中式8+分布式15）&lt;/td&gt;
 &lt;td&gt;达梦/崖山/GaussDB/GoldenDB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;按出现次数（入围≥2次）&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;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;达梦&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;南大通用&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;阿里云&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;瀚高&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;腾讯云&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;东方金信&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;海量数据&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;华为云&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;中兴(GoldenDB)&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;OceanBase&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;金仓&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;神通&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;虚谷&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;崖山&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;仅1次&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;/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;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;大厂&lt;/td&gt;
 &lt;td&gt;华为云(GaussDB/TaurusDB/DWS)、阿里云(PolarDB/AnalyticDB)、腾讯云(TDSQL)、中兴(GoldenDB)、OceanBase(蚂蚁)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;独角兽&lt;/td&gt;
 &lt;td&gt;平凯(TiDB)、崖山(深算院)、星环(ArgoDB)、天谋(TimechoDB)、智臾(DolphinDB)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;大甲方&lt;/td&gt;
 &lt;td&gt;平安科技(RASESQL)、中国银联(UPDRDB)、中国移动(磐维+He3DB)、天翼云(TeleDB)&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;/tbody&gt;
&lt;/table&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%bc%80%e9%97%b8%e6%94%be%e6%b0%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这次名单一出，我的感受就四个字：&lt;strong&gt;开闸放水&lt;/strong&gt;。23 款产品，历次最多。几个看点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;平安 RASESQL。&lt;/strong&gt; 最没有想到的一家。平安集团的金融科技能力一直很强，但他们做数据库这事此前几乎没有公开信息。看到榜单上出现 RASESQL 三个字的时候我愣了好几秒。平安这种体量的金融甲方，自研数据库一旦过了国测，内部信创替代路线就多了一条。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;银联 UPDRDB。&lt;/strong&gt; 同样神秘。之前完全不知道银联在做分布式数据库。银联的交易量摆在那，能扛住自己业务的分布式数据库，技术上不会差。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;阿里云 PolarDB for MySQL。&lt;/strong&gt; PolarDB 的 MySQL 兼容版没过是记在许多人心里的。这次过后，PolarDB 三大主线——PG 版、分布式版、MySQL 版——全过了。加上 AnalyticDB，阿里云数据库全家桶基本凑齐。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;移动磐维 + 电信 TeleDB。&lt;/strong&gt; 移动去年已经有 He3DB（中移苏州）通过国测，今年磐维是第二个产品。电信 TeleDB 首次入围。两家运营商都有自家孵化的信创数据库，各自的信创替换压力应该小不少。反倒是联通一直没有动静——可以想见联通的信创战略跟移动电信肯定不一样。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;星环 ArgoDB。&lt;/strong&gt; 星环是大数据/Hadoop 生态起家的，现在分布式数据库也过了国测。曾经顶着&amp;quot;国产大数据基础软件第一股&amp;quot;的光环，市值一度冲到 300 亿+，从数据湖到信创数据库，路线走通了。&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%bd%b1%e5%93%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这次开闸放水，透露出的最重要的信号是——&lt;strong&gt;甲方可以自研数据库&lt;/strong&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;金融行业的银联、平安，电信行业的移动、电信，都成功通过了国测，等于是&amp;quot;研发成功&amp;quot;的金徽章，各单位内部应该都是喜大普奔的状态。而对于外部厂商来说，他们丢失的不只是大客户，准确一点说，&lt;strong&gt;丢失了绝对话语权&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;我知道你困难，也知道你不买不行，所以杀猪刀不磨了，直接换屠龙刀往死里宰&amp;rdquo;——对于成功孵化自研数据库的甲方来说，这种处境就释缓了许多，意义重大。&lt;/p&gt;
&lt;p&gt;至于未来信创方向会怎么变动，谁都说不好。从以前的名单看应该是越来越严（上次数据库名单只过了 3 个），这次反倒意外地开闸放水。下次急剧收拢也不是不可能。不仅是联通，保险行业的太保、人保，甚至金融行业有能力的都可以考虑下场自己手搓一个数据库。&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%bb%a4%e4%ba%ba%e5%94%8f%e5%98%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为我们内核组就坐在我背后，我还算了解一些信创研发的经过。在连续送测均未通过的情况下，整个团队氛围是极其低落的，我相信不止我们是这样，许多送测通不过的团队也是这样。对于金融、电信等行业来说就是有信创要求，但是自研的产品没有过安可，在公司战略层面就没有选择，在团队层面也当然没有了存在价值。所以“过国测”这三个字含金量、影响力都非常大。还好他们过了，真心祝贺他们！RaseSQL No1！&lt;/p&gt;
&lt;p&gt;同时可以看出，信创结果和风向不稳定，变化大，影响大。它决定了一些公司的战略，也决定了许多人的命运。我自己甚至都是这命运轮盘中的一员。&lt;/p&gt;
&lt;p&gt;除了信创名单上的，还有许多不在名单又付出了巨大努力的单位。他们的产品可能很拉，也可能非常好。但国测就是这样严峻的分水岭，一张神秘的入场券——&lt;strong&gt;过与不过，在国内市场，就是两个概念&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;OK，有感而发，可能会删。&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://www.itsec.gov.cn/aqkkcp/cpgg/" target="_blank" rel="noreferrer"&gt;https://www.itsec.gov.cn/aqkkcp/cpgg/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>当 PostgreSQL 成为 AI 的双手——Bruce Momjian 的 MCP Server 实战</title><link>https://lastdba.com/2026/05/27/%E5%BD%93-postgresql-%E6%88%90%E4%B8%BA-ai-%E7%9A%84%E5%8F%8C%E6%89%8Bbruce-momjian-%E7%9A%84-mcp-server-%E5%AE%9E%E6%88%98/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/05/27/%E5%BD%93-postgresql-%E6%88%90%E4%B8%BA-ai-%E7%9A%84%E5%8F%8C%E6%89%8Bbruce-momjian-%E7%9A%84-mcp-server-%E5%AE%9E%E6%88%98/</guid><description>&lt;blockquote&gt;&lt;p&gt;原文：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;，Bruce Momjian，PGDay Armenia 2026，CC BY 4.0。&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;本文AI率80%&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Bruce Momjian（PG core team，写了 20 多年发行注记的那位）最近在 PGDay Armenia 2026 做了一个演讲：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;。70 页幻灯片，信息密度极高。有理论，有实践，是一个不错的借鉴。&lt;/p&gt;</description><content:encoded>&lt;blockquote&gt;&lt;p&gt;原文：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;，Bruce Momjian，PGDay Armenia 2026，CC BY 4.0。&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;本文AI率80%&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Bruce Momjian（PG core team，写了 20 多年发行注记的那位）最近在 PGDay Armenia 2026 做了一个演讲：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;。70 页幻灯片，信息密度极高。有理论，有实践，是一个不错的借鉴。&lt;/p&gt;
&lt;p&gt;直接读是比较费劲的，哪怕是直接让AI解读一下估计也不知道说的是什么，我也是看了一会问了几个问题后才算看明白了。&lt;/p&gt;
&lt;p&gt;这 70 页可以清晰地切成两层——前半部分是理论教学，后半部分是实战 demo。两层之间，关系不大。&lt;/p&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;理论层：用 Transformer 解释 RAG → MCP 的演进（Slide 1-33）
 &lt;div id="理论层用-transformer-解释-rag--mcp-的演进slide-1-33" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%90%86%e8%ae%ba%e5%b1%82%e7%94%a8-transformer-%e8%a7%a3%e9%87%8a-rag--mcp-%e7%9a%84%e6%bc%94%e8%bf%9bslide-1-33" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;理论层占了近一半篇幅，从 LLM 基本原理讲到 MCP 的工作方式。Outline 很清楚：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/outline.png" alt="演讲大纲：Generative AI → LLM 局限 → RAG → MCP → MCP Server 实战" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;RAG vs MCP：一句话说清
 &lt;div id="rag-vs-mcp一句话说清" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-vs-mcp%e4%b8%80%e5%8f%a5%e8%af%9d%e8%af%b4%e6%b8%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;RAG 的流程大家都熟了：程序员决定查什么数据 → 检索结果拼到 system prompt → LLM 读完后生成回答。&lt;strong&gt;预编排&lt;/strong&gt;——LLM 能看到什么，在用户提问之前就定好了。&lt;/p&gt;
&lt;p&gt;MCP 不一样。工具描述注册给 LLM，LLM 在生成过程中&lt;strong&gt;自己判断&lt;/strong&gt;要不要调工具、调哪个。&lt;strong&gt;动态决策&lt;/strong&gt;——程序员只负责暴露工具，LLM 负责编排。&lt;/p&gt;
&lt;p&gt;Bruce 用一句话总结：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;RAG 只能做程序员预设的事。MCP 可以根据输出质量动态调整，可以迭代调用多个工具，还可以触发外部任务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;&amp;ldquo;是词还是 MCP&amp;rdquo;——那套向量嵌入图解
 &lt;div id="是词还是-mcp那套向量嵌入图解" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%98%af%e8%af%8d%e8%bf%98%e6%98%af-mcp%e9%82%a3%e5%a5%97%e5%90%91%e9%87%8f%e5%b5%8c%e5%85%a5%e5%9b%be%e8%a7%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Slide 18-33 是理论层最核心的部分。Bruce 画了一套详细的 Transformer 内部流程图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/mcp-servers.png" alt="MCP Server 作为 Tool Embedding Vectors 注册到向量空间" /&gt;&lt;/p&gt;
&lt;p&gt;他的逻辑是：把每个 MCP tool 的描述文本（比如 &amp;ldquo;Return the radiation level (CPM) at 13 Roberts Road&amp;hellip;&amp;quot;）用文本嵌入模型向量化，塞进 attention 层的向量空间里。然后在每一步推理时，output vector 去匹配最近似的向量——&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/word-or-mcp.png" alt="最近似向量可能是文本 token，也可能是 MCP tool" /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&amp;ldquo;The closest vector might be a word or an MCP.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&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%e6%a8%a1%e5%9e%8b%e5%af%b9%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这是我最疑惑的地方，以下是我的浅见。&lt;/p&gt;
&lt;p&gt;Bruce 这 15 页 slides 画得很好看，但如果当工程实现去理解，是有问题的：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① MCP tool 不需要&amp;quot;嵌入&amp;rdquo;。&lt;/strong&gt; 实际工程中，tool 定义是作为文本直接写在 system prompt 里的。LLM 读到 &amp;ldquo;你有这些工具：geiger()、get_pretzel_inventory()&amp;hellip;&amp;quot;，靠语义理解决定什么时候调。不需要把 tool 描述算成向量，不需要和词向量做余弦距离比较。Bruce 这套教学模型的本质是把&amp;quot;LLM 决策&amp;quot;解释成&amp;quot;向量最近似匹配&amp;rdquo;，这更像 retrieval 的范式而不是 generation 的范式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Attention 不产出&amp;quot;查最近似&amp;quot;的操作。&lt;/strong&gt; &lt;code&gt;output = Σ(softmax(Q·K) × V)&lt;/code&gt;，产出的是一个加权混合后的上下文向量。没有&amp;quot;在词向量表和 tool 向量表里二选一&amp;quot;这一步。LLM 选工具的实际机制是 attention 产出 hidden state → LM head → softmax over 词表 → 输出 tool call JSON。从来没有在&amp;quot;词和 tool 之间二选一&amp;quot;，只有在整个词表上做 softmax。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ system prompt 和 user prompt 在 attention 里没有边界。&lt;/strong&gt; Token 序列就是 token 序列，attention block 对所有 token 一视同仁做 Q·K 点积。不存在&amp;quot;system 区&amp;quot;和&amp;quot;user 区&amp;quot;。&lt;/p&gt;
&lt;p&gt;所以这 33 页理论层，可以看作 Bruce 给非 AI 背景的 DBA 做的一个教学简化模型——好看、好懂，但别当架构图用。MCP 真正革命性的地方在&lt;strong&gt;协议标准化&lt;/strong&gt;（统一的 tool 注册/发现/调用规范），不在向量化的 trick。&lt;/p&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;实践层：两个能跑的 demo（Slide 34-69）
 &lt;div id="实践层两个能跑的-demoslide-34-69" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e8%b7%b5%e5%b1%82%e4%b8%a4%e4%b8%aa%e8%83%bd%e8%b7%91%e7%9a%84-demoslide-34-69" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;从 Slide 34 开始，风格突变——全是代码、终端输出、硬件照片。理论层那套 Transformer 向量模型完全消失了，取而代之的是 &lt;code&gt;curl&lt;/code&gt;、&lt;code&gt;psql&lt;/code&gt;、Perl 脚本。&lt;/p&gt;
&lt;p&gt;两层之间的唯一联系是&amp;quot;它们都在讲 MCP&amp;quot;，但理论层画的向量匹配机制和实战中的实现方式几乎是两套逻辑。 这可能正是 Bruce 演讲的张力所在——理论层让你理解 MCP 为什么比 RAG 强，实践层告诉你现在怎么落地。&lt;/p&gt;

&lt;h2 class="relative group"&gt;Demo 1：让 ChatGPT 读取真实世界的盖革计数器
 &lt;div id="demo-1让-chatgpt-读取真实世界的盖革计数器" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#demo-1%e8%ae%a9-chatgpt-%e8%af%bb%e5%8f%96%e7%9c%9f%e5%ae%9e%e4%b8%96%e7%95%8c%e7%9a%84%e7%9b%96%e9%9d%a9%e8%ae%a1%e6%95%b0%e5%99%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Bruce 在自家院子里架了一台 GQ GMC-800 盖革计数器（测辐射的），USB 接树莓派，每 15 分钟测一次环境辐射。先看 ChatGPT 用 MCP 调用真实数据的效果：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/chatgpt-weather.png" alt="ChatGPT 通过 MCP 查询天气" /&gt;&lt;/p&gt;
&lt;p&gt;MCP 可以调用外部工具获取实时数据——这是 RAG 做不到的。&lt;/p&gt;
&lt;p&gt;接上硬件：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/geiger-counter.png" alt="GQ GMC-800 盖革计数器" /&gt;&lt;/p&gt;
&lt;p&gt;用 &lt;strong&gt;fastmcp&lt;/strong&gt; 写了 Python 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-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fastmcp &lt;span style="color:#f92672"&gt;import&lt;/span&gt; FastMCP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FastMCP(&lt;span style="color:#e6db74"&gt;&amp;#34;Geiger counter MCP server&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:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;geiger&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Return the radiation level (CPM) at 13 Roberts Road, Newtown Square, PA, USA&amp;#34;&amp;#34;&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;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/var/lib/postgresql/tmp/geiger&amp;#34;&lt;/span&gt;, shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;底层是一个 Perl 脚本，往串口发 &lt;code&gt;&amp;lt;GETCPM&amp;gt;&amp;gt;&lt;/code&gt; 指令，读回 4 字节 CPM 值。Apache 做 443 端口反代（OpenAI 只跟 443 通信），注册到 ChatGPT 后：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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: 13 Roberts Road 的辐射水平是多少？
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: 我没有这个位置的公开数据……
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: 用我的 custom app
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: [调用 geiger tool] → 14 CPM。正常环境背景辐射（5-25 CPM）。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: 测五次，给我平均值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: [调用 ×5] 15 16 13 15 15 → 平均 14.8 CPM&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;ol&gt;
&lt;li&gt;&lt;strong&gt;LLM 可以迭代调工具做计算&lt;/strong&gt;——RAG 是一次性塞数据，MCP 是&amp;quot;调 → 拿结果 → 判断 → 再调 → 算&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户必须显式授权&lt;/strong&gt;——第一次问的时候 ChatGPT 没说&amp;quot;我有你的盖革计数器数据&amp;quot;，直到说 &amp;ldquo;use my custom app&amp;rdquo; 才触发 tool call。安全模型很保守&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;Demo 2：用 PG 做椒盐卷饼店的库存系统
 &lt;div id="demo-2用-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="#demo-2%e7%94%a8-pg-%e5%81%9a%e6%a4%92%e7%9b%90%e5%8d%b7%e9%a5%bc%e5%ba%97%e7%9a%84%e5%ba%93%e5%ad%98%e7%b3%bb%e7%bb%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从硬件回到软件。建一个椒盐卷饼（pretzel）库存库：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pretzel (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; quantity INTEGER &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (quantity &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;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; pretzel &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;); &lt;span style="color:#75715e"&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;MCP tool 直接用 &lt;code&gt;psql&lt;/code&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-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_pretzel_inventory&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Return the number of unsold pretzels&amp;#34;&amp;#34;&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;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;SELECT quantity FROM pretzel;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&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&gt;&lt;/span&gt;&lt;span style="display: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;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sold_one_pretzel&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Call this when a pretzel is sold; reduces inventory by one&amp;#34;&amp;#34;&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;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;UPDATE pretzel SET quantity = quantity - 1;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&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&gt;&lt;/span&gt;&lt;span style="display: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;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;baked_6_pretzels&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Call this when a tray of 6 pretzels is baked; increases inventory&amp;#34;&amp;#34;&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;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;UPDATE pretzel SET quantity = quantity + 6;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&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&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: How many pretzels available?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: 0 pretzels.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I just baked a tray → 6 pretzels
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold two → 4 remaining
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold four → 0 remaining
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold one pretzel → ERROR! CHECK constraint 阻止了 quantity 变负数&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;LLM 不直接写 SQL，而是调你预先定义的受控接口。PG 的 CHECK 约束天然构成了一个安全兜底——即使 LLM 被诱导调了不该调的函数，数据库层的约束还能挡一道。&lt;/p&gt;
&lt;p&gt;但也暴露了问题：LLM 忠实执行了 &lt;code&gt;sold_one_pretzel&lt;/code&gt;，但不会预判&amp;quot;库存已经是 0 了调了会报错&amp;quot;。&lt;strong&gt;MCP 是执行层，不是推理层。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;

&lt;h1 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%9f%e4%ba%a7%e8%bf%98%e5%b7%ae%e5%a4%9a%e8%bf%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;Bruce 在最后一页坦承了当前实现的局限：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有认证&lt;/strong&gt;——谁都可以调你的 MCP Server&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有参数化&lt;/strong&gt;——三个 tool 都是无参函数，现实中的 tool 需要传参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态 SQL 没做安全限制&lt;/strong&gt;——工具描述声明了语义，但 LLM 可能被注入恶意内容&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接池、事务管理、频率限制&lt;/strong&gt;——一概没考虑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两篇值得读的实践经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pgedge.com/blog/lessons-learned-writing-an-mcp-server-for-postgresql" target="_blank" rel="noreferrer"&gt;pgedge.com: Lessons Learned Writing an MCP Server for PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cardinalops.com/blog/mcp-defaults-hidden-dangers-of-remote-deployment/" target="_blank" rel="noreferrer"&gt;CardinalOps: MCP Defaults — Hidden Dangers of Remote Deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;

&lt;h1 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%a4%e5%b1%82%e4%b9%8b%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;回头看这 70 页幻灯片，最有趣的不是任何一个 demo，而是MCP的理论思路和动手说明MCP能做什么：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;理论层用 Transformer 向量空间解释&amp;quot;LLM 如何在词和工具之间做选择&amp;quot;——这是教学模型&lt;/li&gt;
&lt;li&gt;实践层用 &lt;code&gt;psql&lt;/code&gt;、&lt;code&gt;curl&lt;/code&gt;、Perl 脚本去落地——这是工程实现&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而真正的 MCP 机制——tool 定义当文本塞 system prompt、LLM 靠语义理解决定调哪个、输出 tool call JSON——应该是不需要理论层那套向量嵌入模型。两层之间，Bruce 没有画出来连接线。这可能不是 bug，是 feature。&lt;/p&gt;</content:encoded></item><item><title>个人博客上线</title><link>https://lastdba.com/2026/05/16/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E4%B8%8A%E7%BA%BF/</link><pubDate>Sat, 16 May 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/05/16/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E4%B8%8A%E7%BA%BF/</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%b8%8a%e7%ba%bf%e5%95%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;博客终于上线了。&lt;/p&gt;
&lt;p&gt;地址：&lt;a href="https://lastdba.com" target="_blank" rel="noreferrer"&gt;https://lastdba.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;国内可以访问，手机访问也友好&lt;/p&gt;
&lt;p&gt;76 篇文章，都是这几年写 PostgreSQL 的东西——案例、内功、源码、论文精读。&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%b8%8a%e7%ba%bf%e5%95%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;博客终于上线了。&lt;/p&gt;
&lt;p&gt;地址：&lt;a href="https://lastdba.com" target="_blank" rel="noreferrer"&gt;https://lastdba.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;国内可以访问，手机访问也友好&lt;/p&gt;
&lt;p&gt;76 篇文章，都是这几年写 PostgreSQL 的东西——案例、内功、源码、论文精读。&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="#%e4%ba%ae%e7%82%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;界面漂亮&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;界面简约，阅读友好，搜索功能也比较有用&lt;/p&gt;
&lt;p&gt;

 


&lt;img src="https://lastdba.com/img/image-20260517000626083.png" alt="image-20260517000626083" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;框架：Jekyll → Hugo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一版：Jekyll + minima 主题 + 2000 行 CSS&lt;/p&gt;
&lt;p&gt;第二版：Hugo + Blowfish 主题 + 0 行 CSS&lt;/p&gt;
&lt;p&gt;第一版其实也不错，就是自己搞UI很费劲，想到老冯之前写过一个文章关于网站架构选择的，我直接就上去白嫖了。把架构跟AI说明，让它偷学vonng.com，页面质感提升了一个档次，后面再调整调整细节就收工了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;域名：github.io → lastdba.com&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;买了 &lt;code&gt;lastdba.com&lt;/code&gt;，配了 Cloudflare。GitHub Pages 绑自定义域名，免费 HTTPS 证书，全自动续。不用科学上网也可以访问了！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图片本地化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原来文章里的图片散落在各个地方——CSDN 的 CDN、GitHub PicBed、墨天轮 OSS。CSDN 有防盗链，不给看。GitHub PicBed又是外网的，国内经常加载不出来。这次让AI搞到本地路径，以后再也不怕图床跑路。跨网访问也不会有图片加载不出来的问题，very good。&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%8a%e7%ba%bf%e6%84%9f%e6%82%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;其实博客网址以前也搞过，白嫖一个博客网站项目然后用GitHub Pages就可以搭建出来，域名是 &lt;code&gt;liuzhilong62.github.io/blogs&lt;/code&gt;。但是由于个人有些质感癖（不是），效果一般般我就下线了，后面直接把github仓库当博客网址用，pages都没有搞。最近由于各种原因时间比较多，再次想起这个事情，就用hermes从头开始弄博客网站。&lt;/p&gt;
&lt;p&gt;作为一个DBA，后端工程师，什么Jekyll，Hugo，Blowfish，css这些前端的东西我完全不懂，我只需要给Hermes目标，然后它做，它跟我说啥我也听不懂（当然也不好意思跟它说我搞不懂），基本就是&amp;quot;你继续&amp;quot;，我网页端看下效果满意就行，偶尔会&amp;quot;回退这个&amp;quot;。&lt;/p&gt;
&lt;p&gt;说实话，换 Hugo 最大的感受不是技术上的，而是「不要重新发明轮子」。之前花了很多时间手写暗色模式、TOC、搜索，结果发现换个主题全自带，写得还不如人家好看。&lt;/p&gt;
&lt;p&gt;另外，&lt;code&gt;lastdba.com&lt;/code&gt; 这个域名挂上去之后，博客突然有了一种「正式感」。以前 &lt;code&gt;liuzhilong62.github.io/blogs&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%8a%b1%e4%ba%86%e5%a4%9a%e5%b0%91%e9%92%b1" 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;&lt;code&gt;lastdba.com&lt;/code&gt; 域名（Cloudflare，1年）&lt;/td&gt;
 &lt;td&gt;¥70&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GitHub Pages 托管&lt;/td&gt;
 &lt;td&gt;¥0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hugo 框架&lt;/td&gt;
 &lt;td&gt;¥0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Blowfish 主题&lt;/td&gt;
 &lt;td&gt;¥0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cloudflare DNS + CDN&lt;/td&gt;
 &lt;td&gt;¥0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;token&lt;/td&gt;
 &lt;td&gt;¥60&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;合计&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;¥130&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这可能是性价比最高的个人网站方案了。&lt;/p&gt;
&lt;hr&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;有些细节可能没有打磨好，欢迎反馈bug，优化建议&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="#%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://vonng.com/" target="_blank" rel="noreferrer"&gt;https://vonng.com/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>案例-起库失败和sysv共享内存</title><link>https://lastdba.com/2026/03/09/%E6%A1%88%E4%BE%8B-%E8%B5%B7%E5%BA%93%E5%A4%B1%E8%B4%A5%E5%92%8Csysv%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/03/09/%E6%A1%88%E4%BE%8B-%E8%B5%B7%E5%BA%93%E5%A4%B1%E8%B4%A5%E5%92%8Csysv%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98/</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;数据库实例RSS内存打满，日志有OOM信息，库挂了。这里不分析OOM原因。&lt;/p&gt;
&lt;p&gt;但是起库的时候失败，从日志来看总共起库4、5次都失败：&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;数据库实例RSS内存打满，日志有OOM信息，库挂了。这里不分析OOM原因。&lt;/p&gt;
&lt;p&gt;但是起库的时候失败，从日志来看总共起库4、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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:15:21 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;578272&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 2048, ID 1328250881&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:15:21 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;578272&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Terminate any old server processes associated with data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:15:21 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;578272&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: database system is shut down
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:21:03 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;658824&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 2048, ID 1328250881&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:21:03 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;658824&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Terminate any old server processes associated with data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:21:03 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;658824&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: database system is shut down
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:31:12 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;794791&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: redirecting log output to logging collector process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:31:12 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;794791&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Future log output will appear in directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data/pg_log&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:31:37 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;801049&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: lock file &lt;span style="color:#e6db74"&gt;&amp;#34;postmaster.pid&amp;#34;&lt;/span&gt; already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:31:37 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;801049&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Is another postmaster &lt;span style="color:#f92672"&gt;(&lt;/span&gt;PID 794791&lt;span style="color:#f92672"&gt;)&lt;/span&gt; running in data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&amp;#34;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:32:34 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;814396&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: lock file &lt;span style="color:#e6db74"&gt;&amp;#34;postmaster.pid&amp;#34;&lt;/span&gt; already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-02-12 09:32:34 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;814396&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Is another postmaster &lt;span style="color:#f92672"&gt;(&lt;/span&gt;PID 794791&lt;span style="color:#f92672"&gt;)&lt;/span&gt; running in data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&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;启动成功是因为DBA在起库前执行&lt;code&gt;ipcrm -m xxx&lt;/code&gt;，然后启动成功的。&lt;/p&gt;
&lt;p&gt;虽然快速解决问题，但是仍有很多疑问：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么这种场景在现实种不算太多见？&lt;/li&gt;
&lt;li&gt;start.log起库报错有2类，分别对应什么操作和逻辑？&lt;/li&gt;
&lt;li&gt;如果PM都不在了共享内存还可以存在吗？&lt;/li&gt;
&lt;li&gt;这段共享内存如何定位和清理？&lt;/li&gt;
&lt;li&gt;PG共享内存有多段，这段共享内存是哪一段？&lt;/li&gt;
&lt;li&gt;除了ipcrm -m还有其他起库办法吗&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;报错分析：&lt;code&gt;pre-existing shared memory block&lt;/code&gt;
 &lt;div id="报错分析pre-existing-shared-memory-block" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8a%a5%e9%94%99%e5%88%86%e6%9e%90pre-existing-shared-memory-block" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;3种共享内存
 &lt;div id="3种共享内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3%e7%a7%8d%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;正常来说，PG起库后共享内存有三段。&lt;/p&gt;
&lt;p&gt;以默认“&lt;code&gt;shared_memory_type='mmap'&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;## 从PG申请的虚拟内存查看PG真实使用共享内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;head -1 $PGDATA/postmaster.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/smaps | grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;\-s&amp;#34;&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;2b61b0563000-2b61b0564000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;116293664&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;2b61b057f000-2b61b05b3000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:12 &lt;span style="color:#ae81ff"&gt;1501001168&lt;/span&gt; /dev/shm/PostgreSQL.1193490778
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b61bbac2000-2b61fa67a000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;1500999610&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如上所示，从上往下分别是&lt;strong&gt;SYSV起库使用的共享内存&lt;/strong&gt;、&lt;strong&gt;并行计算使用的共享内存&lt;/strong&gt;、&lt;strong&gt;sharedbuffers使用的共享内存&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果sharedbuffers使用了大页，或者sharedbuffers type是SYSV而不是mmap，输出会稍微有些区别。&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;2aaaaac00000-2aba9ca00000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:0e &lt;span style="color:#ae81ff"&gt;48453452&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;2b08f2eea000-2b08f2eeb000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;50692152&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;2b08f2f05000-2b08f302d000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:12 &lt;span style="color:#ae81ff"&gt;48436142&lt;/span&gt; /dev/shm/PostgreSQL.1345689218&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;shared_memory_type = &amp;lsquo;sysv&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b03b3ceb000-2b03b3d1f000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:12 &lt;span style="color:#ae81ff"&gt;1572332304&lt;/span&gt; /dev/shm/PostgreSQL.2883611352
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2b03bf0c2000-2b03fdc7a000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;143917075&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;/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;PG共享内存配置&lt;/th&gt;
 &lt;th&gt;smaps共享内存段数&lt;/th&gt;
 &lt;th&gt;sharedbuffers smaps&lt;/th&gt;
 &lt;th&gt;sysv smaps&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;shared_memory_type=mmap，没有大页&lt;/td&gt;
 &lt;td&gt;3段共享内存&lt;/td&gt;
 &lt;td&gt;/dev/zero&lt;/td&gt;
 &lt;td&gt;/SYSV00001000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;shared_memory_type=sysv，没有大页&lt;/td&gt;
 &lt;td&gt;2段共享内存&lt;/td&gt;
 &lt;td&gt;/SYSV00001000&lt;/td&gt;
 &lt;td&gt;/SYSV00001000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;shared_memory_type=mmap，有大页&lt;/td&gt;
 &lt;td&gt;3段共享内存&lt;/td&gt;
 &lt;td&gt;/anon_hugepage&lt;/td&gt;
 &lt;td&gt;/SYSV00001000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;shared_memory_type=sysv，有大页&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;code&gt;pre-existing shared memory block&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="#%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;源码搜报错很容易找到关键代码位置：&lt;code&gt;src/backend/port/sysv_shmem.c&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;首先理解sysv shmem是干嘛的，以下截取自零散的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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;We still require a SysV shmem block to
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * exist, though, because mmap&amp;#39;d shmem provides no way to find out how
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * many processes are attached, which we need for interlocking purposes.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * As of PostgreSQL 9.3, we normally allocate only a very small amount of
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * System V shared memory, and only for the purposes of providing an
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * interlock to protect the data directory. The real shared memory block
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * is allocated using mmap(). This works around the problem that many
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * systems have very low limits on the amount of System V shared memory
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * that can be allocated. Even a limit of a few megabytes will be enough
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * to run many copies of PostgreSQL without needing to adjust system settings.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;sysv shmem可以找共享内存是否是attached，mmap不能实现此功能&lt;/li&gt;
&lt;li&gt;这段&lt;strong&gt;sysv shmem是用来保护datadir的&lt;/strong&gt;；shared buffer用的是mmap（默认）不是sysv&lt;/li&gt;
&lt;li&gt;这段sysv shmem非常小（从虚拟内存地址可以看出申请的是4K=2b61b0563000-2b61b0564000）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;再看shm的状态enum：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;	SHMSTATE_ANALYSIS_FAILURE,	&lt;span style="color:#75715e"&gt;/* unexpected failure to analyze the ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SHMSTATE_ATTACHED,			&lt;span style="color:#75715e"&gt;/* pertinent to DataDir, has attached PIDs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SHMSTATE_ENOENT,			&lt;span style="color:#75715e"&gt;/* no segment of that ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SHMSTATE_FOREIGN,			&lt;span style="color:#75715e"&gt;/* exists, but not pertinent to DataDir */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SHMSTATE_UNATTACHED			&lt;span style="color:#75715e"&gt;/* pertinent to DataDir, no attached PIDs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} IpcMemoryState;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;主要是关注ATTACHED,FOREIGN,UNATTACHED。&lt;/p&gt;
&lt;p&gt;sysv shmem是用来保护datadir目录的，比如常见的场景是要确认这个目录不会被跑2个实例。既然有shmem共享内存，那么因为各种奇怪原因，这个共享内存也有可能不是这个目录或者这个进程的，所有是FOREIGN状态。如果共享内存对应到datadir了，但没有进程在运行，那么应该是UNATTACHED，有进程运行那么是ATTACHED。&lt;/p&gt;
&lt;p&gt;这时再来看&lt;code&gt;PGSharedMemoryCreate&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;PGShmemHeader &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;PGSharedMemoryCreate&lt;/span&gt;(Size size,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 PGShmemHeader &lt;span style="color:#f92672"&gt;**&lt;/span&gt;shim)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (;;) &lt;span 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; shmid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shmget&lt;/span&gt;(NextShmemSegID, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(PGShmemHeader), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//shmget获取shmem共享内存并返回shmid
&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; (shmid &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;			oldhdr &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;			state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SHMSTATE_FOREIGN;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;			state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PGSharedMemoryAttach&lt;/span&gt;(shmid, NULL, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;oldhdr);&lt;span style="color:#75715e"&gt;//找到这段shmem共享内存的状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (state)&lt;span 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;//这里只展示了2种，shm有attach和没有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;case&lt;/span&gt; SHMSTATE_ATTACHED: &lt;span style="color:#75715e"&gt;//shm有attach的情况，抛出报错（也就是问题现象出现的报错）
&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;(FATAL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						(&lt;span style="color:#a6e22e"&gt;errcode&lt;/span&gt;(ERRCODE_LOCK_FILE_EXISTS),
&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;pre-existing shared memory block (key %lu, ID %lu) is still in use&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;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;) NextShmemSegID,
&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;long&lt;/span&gt;) shmid),
&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;Terminate any old server processes associated with data directory &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;.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 DataDir)));
&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; SHMSTATE_UNATTACHED:&lt;span style="color:#75715e"&gt;//shm是unattach的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 segment pertains to DataDir, and every process that had
&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 it has died or detached. Zap it, if possible, and any
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * associated dynamic shared memory segments, as well. 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;				 * shouldn&amp;#39;t fail, but if it does, assume the segment belongs
&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 someone else after all, and try the next candidate.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * Otherwise, try again to create the segment. That may fail
&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 some other process creates the same shmem key before 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;				 * do, in which case we&amp;#39;ll try the next key.
&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;//代表内存段关联Data目录，且没有进程还持有这个段
&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; (oldhdr&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;dsm_control &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:#a6e22e"&gt;dsm_cleanup_using_control_segment&lt;/span&gt;(oldhdr&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;dsm_control);
&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;shmctl&lt;/span&gt;(shmid, IPC_RMID, NULL) &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;					NextShmemSegID&lt;span style="color:#f92672"&gt;++&lt;/span&gt;; &lt;span style="color:#75715e"&gt;//注意这里的ShmemSegID递增循环
&lt;/span&gt;&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;span 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;可以看到shmem attached时会抛出报错。如果没有attach，会无限循环尝试清理这段共享内存并shmemsegid+1申请新的共享内存。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一种情况对应这个故障&lt;/li&gt;
&lt;li&gt;第二种情况对应实例崩溃仍然可以正常起库&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 class="relative group"&gt;sysv shmem
 &lt;div id="sysv-shmem" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sysv-shmem" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;PG10及以后postmaster.pid，sysv_shmem相关的逻辑大改，10以后基本没有变过。本文只分析了10以后的逻辑。&lt;/p&gt;
&lt;p&gt;pidfile.h:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 LOCK_FILE_LINE_SHMEM_KEY	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;sysv_shmem.c，InternalIpcMemoryCreate()：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#66d9ef"&gt;char&lt;/span&gt;		line[&lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;(line, &lt;span style="color:#e6db74"&gt;&amp;#34;%9lu %9lu&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;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;) memKey, (&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;) shmid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;AddToDataDirLockFile&lt;/span&gt;(LOCK_FILE_LINE_SHMEM_KEY, line);
&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;从源码可以看出，shmem信息保存在postmaster.pid文件第七行，分别写的是shmkey和shmid。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;&amp;gt; cat postmaster.pid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;242712&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1772698474&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;8531&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.0.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt; &lt;span style="color:#75715e"&gt;# &amp;lt;----here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ready&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;什么是shmkey和shmid
 &lt;div id="什么是shmkey和shmid" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%afshmkey%e5%92%8cshmid" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;在pg源码中是这样调用的，InternalIpcMemoryCreate()：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;			shmid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shmget&lt;/span&gt;(memKey, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, IPC_CREAT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IPC_EXCL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IPCProtection);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;PG以shmkey/memkey为种子key，向内核申请shmem并返回唯一标识符shmid&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;shmid高度依赖服务器或者说服务器内存的状态。对于PG来说，快速重启实例，前后的shmid可能会相同或者+1，这跟linux内核机制相关；服务器重启那就完全不一样。&lt;/p&gt;
&lt;p&gt;可以这样增加理解度：&lt;strong&gt;无论服务器是否重启，shmkey/memkey都可以是固定值，因为毕竟是用户输入（即PG）；而在服务器重启前后，即便传入同一shmkey，获取的shmid不太可能是同一值。&lt;/strong&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;PG是怎么拿shmkey的
 &lt;div id="pg是怎么拿shmkey的" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%98%af%e6%80%8e%e4%b9%88%e6%8b%bfshmkey%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;PGSharedMemoryCreate()：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;	 * We use the data directory&amp;#39;s ID info (inode and device numbers) 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;	 * positively identify shmem segments associated with this data dir, 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;	 * also as seeds for searching for a free shmem key.
&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;stat&lt;/span&gt;(DataDir, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;statbuf) &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 style="color:#a6e22e"&gt;ereport&lt;/span&gt;(FATAL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;errcode_for_file_access&lt;/span&gt;(),
&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;could not stat data directory &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;: %m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						DataDir)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Loop till we find a free IPC key. Trust CreateDataDirLockFile() 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;	 * ensure no more than one postmaster per data directory can enter 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;	 * loop simultaneously. (CreateDataDirLockFile() does not entirely 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, but prefer fixing it over coping 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;	NextShmemSegID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; statbuf.st_ino;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		IpcMemoryId shmid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		PGShmemHeader &lt;span style="color:#f92672"&gt;*&lt;/span&gt;oldhdr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		IpcMemoryState 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;/* Try to create new segment */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		memAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;InternalIpcMemoryCreate&lt;/span&gt;(NextShmemSegID, sysvsize);
&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; (memAddress)
&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;/* successful create and attach */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 shared memory and possibly remove and recreate */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * shmget() failure is typically EACCES, hence SHMSTATE_FOREIGN.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * ENOENT, a narrow possibility, implies SHMSTATE_ENOENT, but one 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;		 * safely treat SHMSTATE_ENOENT like SHMSTATE_FOREIGN.
&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;		shmid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shmget&lt;/span&gt;(NextShmemSegID, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(PGShmemHeader), &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;PG通过stat获取datadir的状态，其中包含datadir的inode，PG直接将datadir.inode当作shmkey。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在PG中shmem key跟datadir的inode强相关，一般情况下shmem key=datadir inode&lt;/strong&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ls -id $PGDATA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; /lzlcloud/pg8574/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat postmaster.pid |head -7|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917090&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到datadir.inode=shmkey=4096。&lt;/p&gt;

&lt;h4 class="relative group"&gt;PG在云环境下的shmkey
 &lt;div id="pg在云环境下的shmkey" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%9c%a8%e4%ba%91%e7%8e%af%e5%a2%83%e4%b8%8b%e7%9a%84shmkey" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;上面说一般情况shmid=datadir.inode，实际上这在云环境中基本不是这个情况。&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;&amp;gt; ls -id /lzlcloud/pg8298/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; /lzlcloud/pg8298/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ls -id /lzlcloud/pg8388/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; /lzlcloud/pg8388/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ls -id /lzlcloud/pg8095/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; /lzlcloud/pg8095/data&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;&amp;gt; cat /lzlcloud/pg8298/data/postmaster.pid|head -7|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;971833391&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat /lzlcloud/pg8388/data/postmaster.pid|head -7|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;62128161&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat /lzlcloud/pg8095/data/postmaster.pid|head -7|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4098&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143163441&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;data盘dir的inode都是4096，而shmkey是4096、4097、4098&lt;/p&gt;
&lt;p&gt;why?&lt;/p&gt;
&lt;p&gt;inode的问题跟磁盘的文件系统有关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个文件系统有独立的inode&lt;/li&gt;
&lt;li&gt;文件系统预留了一些inode，前几位是不能使用的。根据不同的挂载方式，我们data盘真正的inode从4096开始&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说datadir.inode=4096这是我们云环境磁盘挂载的默认行为。其他环境可能不一样，未深入分析。不过以相同文件系统和相同方式挂载挂载pg datadir的话，仍有可能inode数值相等。&lt;/p&gt;
&lt;p&gt;shmkey的问题跟PG源码相关,PGSharedMemoryCreate()：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span 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; NextShmemSegID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; statbuf.st_ino;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		shmid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shmget&lt;/span&gt;(NextShmemSegID, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(PGShmemHeader), &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;switch&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:#66d9ef"&gt;case&lt;/span&gt; SHMSTATE_FOREIGN:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				NextShmemSegID&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;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;本来shmkey=datadir.inode，但是由于可能申请到shmem是foreign的，所以shmkey+1再申请一次。&lt;/p&gt;
&lt;p&gt;例如postmaster.pid文件shmkey=4097的那个实例，它起库时shmkey=4096，但是发现shmid那个内存段被其他实例使用了（就是另一个shmkey=4096的PG实例），它让shmkey+1再申请了另一个shmid共享内存段。&lt;/p&gt;
&lt;p&gt;同理shmkey=4098的那个实例加了2次才找到空闲的shmkey对应的shmid。&lt;/p&gt;

&lt;h3 class="relative group"&gt;shmid的关联性
 &lt;div id="shmid的关联性" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shmid%e7%9a%84%e5%85%b3%e8%81%94%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;sysv的shmid可以在&lt;strong&gt;起库的报错日志&lt;/strong&gt;、&lt;strong&gt;postmaster.pid文件第7行&lt;/strong&gt;、&lt;strong&gt;虚拟内存地址smaps&lt;/strong&gt;中均可以找到，并通过sysv共享内存命令的&lt;code&gt;ipcs&lt;/code&gt;命令查看和&lt;code&gt;ipcrm&lt;/code&gt;命令清理。&lt;/p&gt;
&lt;p&gt;示例：注意以下shmid=143917078&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;pg_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-05 16:02:19 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;262388&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 4096, ID 143917078&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;postmaster.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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat postmaster.pid |head -7|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;虚拟内存smaps：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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/&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;head -1 $PGDATA/postmaster.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/smaps | grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;\-s&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2ad2b5189000-2ad2b518a000 rw-s &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; 00:04 &lt;span style="color:#ae81ff"&gt;143917078&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过shmid sysv共享内存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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt; &lt;span style="color:#75715e"&gt;#清理：ipcrm -m shmid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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 Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;242712&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;242712&lt;/span&gt; nattch&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;att_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:14:51 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;det_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:14:49 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;change_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:14:34 &lt;span style="color:#ae81ff"&gt;2026&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" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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%94%9f%e4%ba%a7%e9%97%ae%e9%a2%98%e5%a4%8d%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;持有一个backend进程永不退出，kill -9 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;&amp;gt; cat postmaster.pid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917076&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917076&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmem id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917076&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;241567&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;64757&lt;/span&gt; nattch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; kill -stop &lt;span style="color:#ae81ff"&gt;107648&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; kill -9 &lt;span style="color:#ae81ff"&gt;64757&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917076&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917076&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;252283&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;64757&lt;/span&gt; nattch&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;#nattch != 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;&amp;gt; pg_ctl start -D $PGDATA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-05 16:02:19 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;262388&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 4096, ID 143917076&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 16:02:19 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;262388&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Terminate any old server processes associated with data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stopped waiting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_ctl: could not start server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;nattach=1，实例无法启动。&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%ae%9e%e4%be%8b%e5%a5%94%e6%ba%83%e6%ad%a3%e5%b8%b8%e8%b5%b7%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;其实就是kill实例然后启动&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;&amp;gt; cat postmaster.pid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmem id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;154800&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;134329&lt;/span&gt; nattch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; kill -9 &lt;span style="color:#ae81ff"&gt;134329&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat postmaster.pid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmem id没有改变，shmem仍然存在&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;169360&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;134329&lt;/span&gt; nattch&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;#nattch=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;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmem id没有改变，shmem仍然存在&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; pg_ctl start -D $PGDATA &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_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-05 16:14:34 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;242712&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: redirecting log output to logging collector process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 16:14:34 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;242712&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Future log output will appear in directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data/pg_log&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;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server started
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt; &lt;span style="color:#75715e"&gt;#残留的shmem起库时被清理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ipcs: id &lt;span style="color:#ae81ff"&gt;143917077&lt;/span&gt; not found
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmemid起库时被+1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;273571&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;242712&lt;/span&gt; nattch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; cat postmaster.pid &lt;span style="color:#75715e"&gt;# shmkey不变，shmid+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;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917078&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;正常kill -9然后启动，可以正常启动，残留的shmem会在启动时被清理。shmkey不变是因为inode=4096且shmkey=4096没有被占用，shmid+1这是linux内核行为，至少说明不是使用的同一段shmem。&lt;/p&gt;

&lt;h4 class="relative group"&gt;持有文件但不持有shmem
 &lt;div id="持有文件但不持有shmem" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%81%e6%9c%89%e6%96%87%e4%bb%b6%e4%bd%86%e4%b8%8d%e6%8c%81%e6%9c%89shmem" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;因为起库跟datadir inode相关，inode跟shmem id相关，起库本质上是在&lt;strong&gt;检查shmem是不是被其他进程持有，而不是文件fd是否还被其他进程持有&lt;/strong&gt;。所以这里测试不持有共享内存但持有文件fd的进程logger。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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/77300/smaps | grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;\-s&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;#这是logger进程，检查它没有用共享内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kill -stop &lt;span style="color:#ae81ff"&gt;77300&lt;/span&gt; &lt;span style="color:#75715e"&gt;#stop logger&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kill -9 &lt;span style="color:#ae81ff"&gt;77076&lt;/span&gt; &lt;span style="color:#75715e"&gt;#kill -9 pm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat postmaster.pid &lt;span style="color:#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;77076&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/lzlcloud/pg8531/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1772700343&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;8531&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.0.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;143917080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ready 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917080&lt;/span&gt; &lt;span 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;Shared memory Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;77319&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;77076&lt;/span&gt; nattch&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;att_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 17:27:11 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;det_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 17:27:15 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;change_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:45:43 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&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 -ef|grep &lt;span style="color:#ae81ff"&gt;77300&lt;/span&gt; &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:#ae81ff"&gt;77300&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 16:45 ? 00:00:00 postgresql: lzldb: logger 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;135246&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;46622&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 17:27 pts/1 00:00:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto &lt;span style="color:#ae81ff"&gt;77300&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pg_ctl start -D $PGDATA &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_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-05 17:27:55 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;140497&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: redirecting log output to logging collector process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 17:27:55 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;140497&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Future log output will appear in directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data/pg_log&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;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server started&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;logger持有data目录下的文件，但不关联共享内存，不会阻止起库&lt;/p&gt;

&lt;h4 class="relative group"&gt;删除postmaster.pid文件起库失败
 &lt;div id="删除postmasterpid文件起库失败" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a4postmasterpid%e6%96%87%e4%bb%b6%e8%b5%b7%e5%ba%93%e5%a4%b1%e8%b4%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;流程跟上面差不多：持有1个backend进程，kill -9 PM，删除postmaster.pid文件，起库。&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;waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; server to start....2026-03-06 15:29:48 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;22475&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 4098, ID 171868173&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-06 15:29:48 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;22475&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Terminate any old server processes associated with data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/data&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-06 15:29:48 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;22475&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: database system is shut down&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看出，有僵尸进程持有shmem的情况下，即便删除包含shmid的postmaster.pid文件，PG仍然能找到对应的shmid。&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%b3%e9%97%ad%e4%b8%80%e4%b8%aa%e5%85%b6%e4%bb%96%e5%ba%93%e5%90%af%e5%8a%a8%e5%bd%93%e5%89%8d%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg会分析2个地方shmid是否是当前的&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;以datadir.inode当作shmkey对应的shmid，或者&lt;code&gt;shmkey++&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;postmaster.pid中的shmid&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;即便直接删除postmaster.pid，PG仍然可以知道shmem是不是被其他进程持有。但是我们可以通过datadir.inode和&lt;code&gt;shmkey++&lt;/code&gt;的特性让他起库。&lt;/p&gt;
&lt;p&gt;因为根据之前分析，我们云环境datadir inode都是4096，shmkey不同是因为源码有&lt;code&gt;shmkey++&lt;/code&gt;的逻辑。所以我们可以：&lt;strong&gt;启动或停止一个datadir.inode=4096的PG库，让当前PG库启动时&lt;code&gt;shmkey++&lt;/code&gt;多一个或者少一个，拿到不同的shmid。&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;$ kill -stop &lt;span style="color:#ae81ff"&gt;165245&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kill -9 &lt;span style="color:#ae81ff"&gt;164411&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pg_ctl stop -D /pg8531/data &lt;span style="color:#75715e"&gt;# 停一个其他库&lt;/span&gt;
&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;span style="display:flex;"&gt;&lt;span&gt;$ pg_ctl start -D /pg8574/data &lt;span style="color:#75715e"&gt;# 启动当前库，会失败，因为postmaster.pid没有删除&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rase_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-05 18:22:35 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;196209&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: pre-existing shared memory block &lt;span style="color:#f92672"&gt;(&lt;/span&gt;key 4097, ID 143917087&lt;span style="color:#f92672"&gt;)&lt;/span&gt; is still in use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 18:22:35 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;196209&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Terminate any old server processes associated with data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/pg8574/data&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stopped waiting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rase_ctl: could not start server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Examine the log output.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mv /lzlcloud/pg8574/data/postmaster.pid&lt;span style="color:#f92672"&gt;{&lt;/span&gt;,.bak&lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 删除当前库的postmaster.pid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pg_ctl start -D /lzlcloud/pg8574/data &lt;span style="color:#75715e"&gt;#再起当前库，成功&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 18:23:09 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;207725&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: LOG: redirecting log output to logging collector process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-05 18:23:09 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;207725&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Future log output will appear in directory &lt;span style="color:#e6db74"&gt;&amp;#34;/lzlcloud/pg8574/data/pg_log&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;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server started
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ipcs -m -i &lt;span style="color:#ae81ff"&gt;143917087&lt;/span&gt; &lt;span style="color:#75715e"&gt;#shmid对应的sysv共享内存仍然被我们持有&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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 Segment shmid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;143917087&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cuid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; cgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt; access_perms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; lpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;196209&lt;/span&gt; cpid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;164411&lt;/span&gt; nattch&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;att_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 18:22:35 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;det_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 18:22:35 &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;change_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Thu Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 18:21:04 &lt;span style="color:#ae81ff"&gt;2026&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;这里有个小小的前提，关的其他库不仅要inode=当前库inode，还要其他库shmkey&amp;lt;当前库shmkey。&lt;/p&gt;

&lt;h2 class="relative group"&gt;报错分析：&lt;code&gt;lock file &amp;quot;postmaster.pid&amp;quot; already exists&lt;/code&gt;
 &lt;div id="报错分析lock-file-postmasterpid-already-exists" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8a%a5%e9%94%99%e5%88%86%e6%9e%90lock-file-postmasterpid-already-exists" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这个问题比“共享内存已存在”简单多了。&lt;/p&gt;
&lt;p&gt;起库时本身就会检查lock file、lock file中的pid，CreateLockFile():&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; (other_pid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; my_pid &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; other_pid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; my_p_pid &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;			other_pid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; my_gp_pid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;kill&lt;/span&gt;(other_pid, &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(errno &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; ESRCH &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; errno &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; EPERM))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* lockfile belongs to a live process */&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;(FATAL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						(&lt;span style="color:#a6e22e"&gt;errcode&lt;/span&gt;(ERRCODE_LOCK_FILE_EXISTS),
&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;lock file &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; already exists&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								filename),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 isDDLock &lt;span style="color:#f92672"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 (encoded_pid &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Is another postgres (PID %d) running in data directory &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;?&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;int&lt;/span&gt;) other_pid, refName) &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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Is another postmaster (PID %d) running in data directory &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;?&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;int&lt;/span&gt;) other_pid, refName)) &lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 (encoded_pid &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Is another postgres (PID %d) using socket file &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;?&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;int&lt;/span&gt;) other_pid, refName) &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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Is another postmaster (PID %d) using socket file &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;?&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;int&lt;/span&gt;) other_pid, refName))));
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 start -D /pg8531/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_ctl: another server might be running; trying to start server anyway
&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 start....2026-03-06 15:59:05 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;89145&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: FATAL: lock file &lt;span style="color:#e6db74"&gt;&amp;#34;postmaster.pid&amp;#34;&lt;/span&gt; already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-03-06 15:59:05 CST::@:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;89145&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: HINT: Is another postmaster &lt;span style="color:#f92672"&gt;(&lt;/span&gt;PID 255500&lt;span style="color:#f92672"&gt;)&lt;/span&gt; running in data directory &lt;span style="color:#e6db74"&gt;&amp;#34;/pg8531/data&amp;#34;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stopped waiting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_ctl: could not start server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Examine the log output.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所以故障时的start.log后面几个报错是因为库已经启动了，多启动了几次。&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;p&gt;PG在起库时，会先开辟一个sysv shmem（不是mmap对应的share buffers）以锁定datadir。锁定是通过datadir的inode号当作shmkey通过shmget申请的，并返回shmem唯一标识符shmid。由于可能申请的shmem被其他进程使用，PG会让&lt;code&gt;shmkey++&lt;/code&gt;无限循环指到申请到没有被人占用的shmem。postmaster.pid第七行分别保存shmkey和shmid。在云环境下通常可以看到共享PG实例的shmkey递增的现象，这是因为data盘挂载方式相同使用了相同的inode，&lt;code&gt;shmkey++&lt;/code&gt;导致。&lt;/p&gt;
&lt;p&gt;如果PG实例被意外干掉，shmem不会被清理，正常情况下没有僵尸进程持有共享内存，那么起库会清理这段shmem并正常起库；异常情况下僵尸进程持有共享内存，起库会失败，此时需要介入处理。&lt;/p&gt;
&lt;p&gt;推荐的处理方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ipcrm -m（最推荐）&lt;/li&gt;
&lt;li&gt;lsof找到僵尸进程并kill&lt;/li&gt;
&lt;li&gt;重启主机&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不推荐但可以起库的方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;mv postmaster.pid+关闭一个其他PG库（其他PG库的shmkey&amp;lt;当前PG库）&lt;/li&gt;
&lt;li&gt;mv postmaster.pid+重新挂载data盘并改变inode&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后回答开头的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么这种场景在现实种不算太多见？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实例异常宕机+仍然有僵尸进程没有被清理。有些情况是异常宕机没有僵尸进程，正常起库就行了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;start.log起库报错有2类，分别对应什么操作和逻辑？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;共享内存被占用的报错是因为实例异常宕机+仍然有僵尸进程；postmaster.pid存在的报错是因为起库多次&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果PM都不在了共享内存还可以存在吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PM都不在了共享内存可以存在，PG的进程不一定会自己跑挂或者被OS处理；但是所有进程都不在了共享内存应该不存在&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这段共享内存如何定位和清理？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;起库的start.log可以找到shmid，&lt;code&gt;ipcrm -m $shmid&lt;/code&gt;命令可以清理。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PG共享内存有多段，这段共享内存是哪一段？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;sysv shmem，用于保护datadir，一定存在，参考“三种共享内存”部分。与mmap下的sharebuffers是2个东西。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以通过inode或者文件找到对应的shmem吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LINUX在用户态没有提供通过inode或者文件找到对应shmem的接口（这句话AI含量100%，经过多个模型交叉验证）。PG是通过datadir的inode当作种子shmkey去申请的shmem共享内存，本质上不是通过inode直接找到对应的shmem，PG对shmem共享内存使用自己的寻找机制，但不绝对对应，shkey++就是一个折衷起库逻辑。&lt;/p&gt;</content:encoded></item><item><title>AI时代下的DBA、写作、学习和未来</title><link>https://lastdba.com/2026/01/21/ai%E6%97%B6%E4%BB%A3%E4%B8%8B%E7%9A%84dba%E5%86%99%E4%BD%9C%E5%AD%A6%E4%B9%A0%E5%92%8C%E6%9C%AA%E6%9D%A5/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/01/21/ai%E6%97%B6%E4%BB%A3%E4%B8%8B%E7%9A%84dba%E5%86%99%E4%BD%9C%E5%AD%A6%E4%B9%A0%E5%92%8C%E6%9C%AA%E6%9D%A5/</guid><description>&lt;blockquote&gt;&lt;p&gt;AI率：本篇文章AI率约60%，与AI battle回合约20次&lt;/p&gt;
&lt;p&gt;推荐理由：有一些对AI ops的思考和洞察，所以推荐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 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="#ai%e6%97%b6%e4%bb%a3%e7%9a%84%e5%86%99%e4%bd%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;AI对写博客、写公众号的作者来说，可能是一个致命的打击，因为AI写作实在是太简单。因为我自己就写文章，我自己对AI影响写作习惯也有很多纠结的地方，我也很难受。这里再把以前的对写作的思考拿出来：&lt;/p&gt;</description><content:encoded>&lt;blockquote&gt;&lt;p&gt;AI率：本篇文章AI率约60%，与AI battle回合约20次&lt;/p&gt;
&lt;p&gt;推荐理由：有一些对AI ops的思考和洞察，所以推荐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 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="#ai%e6%97%b6%e4%bb%a3%e7%9a%84%e5%86%99%e4%bd%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;AI对写博客、写公众号的作者来说，可能是一个致命的打击，因为AI写作实在是太简单。因为我自己就写文章，我自己对AI影响写作习惯也有很多纠结的地方，我也很难受。这里再把以前的对写作的思考拿出来：&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;li&gt;为他人/社区，传播知识。好东西要拿出来大家一起看和使用，这是Postgres开源社区的内核所在。鼓励分享，不鼓励藏着掖着，这也是我一直秉持的理念。&lt;/li&gt;
&lt;li&gt;结交圈子。我不是为了这个来，但确实认识了一些小伙伴&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;人力写作已经很难了，在AI时代人力写作约等于地狱模式，就像没有目标地逆行，看不到光在哪，而人们都在往反方向走。我自己当然体验过AI解读、翻译、写成文章，但总感觉那不是我的，或者失去了训练我自己的初心，或者更深层次一点，我想感受到作品的生命力。&lt;/p&gt;
&lt;p&gt;整个DBA圈子的文章可以用鱼龙混杂来形容，写啥的都有。而我自己一直都喜欢内容性文章，偏PG原理和运维的，比如&lt;strong&gt;灿灿和向博&lt;/strong&gt;的文章，我都是翘首以盼每次必细品。一般内容性文章都不会有特别多的流量（灿灿和向博都各自在公众号吐槽过··），我自己也很随缘。&lt;/p&gt;
&lt;p&gt;但是，我上一篇文章《pg运维数据库运维经验2025》涨了很多粉，实属让我惊讶。所以我这几天一直在思考这个问题：&lt;strong&gt;为什么一个人（非AI）写的、非完备的、DBA的、知识性的文章，会有这么多人感兴趣？AI对DBA意味着什么？&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="#%e5%af%b9%e8%bf%90%e7%bb%b4%e7%9a%84%e6%80%9d%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;运维的本质和AI Ops
 &lt;div id="运维的本质和ai-ops" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%9a%84%e6%9c%ac%e8%b4%a8%e5%92%8cai-ops" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;运维要做很多事情，为了减少讨论的范围，我在运维工作中极少一部分&amp;ndash;&lt;strong&gt;故障响应&lt;/strong&gt;，来解读DB Ops的本质。首先我的观点：“&lt;strong&gt;运维不仅仅是技术问题&lt;/strong&gt;”&lt;/p&gt;
&lt;p&gt;很多人通过人会犯错AI也会犯错来解释可以给AI权限让它大胆的干，具体的说是AI的错误率&amp;lt;=人的错误率即可完成替换。我2年前也是这么想的，现在我不这么认为。因为真实环境没有那么简单，至少还有如下因素需要考虑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共识问题。DBA可能误删数据，这确实是共识，但还有一个共识容易忽略。在一般场景下，团队都认为DBA不会去删数据。如何理解呢 ？比如招聘一个DBA，一个负责的团队会考核这个人是不是精神状态正常，然后默认他不会删除数据，并在长期的工作中会这么想，我至少不会时刻都在考虑同事把库删了。但“招聘”一个AI DBA，他没有精神状态，不会有人认为他不会删数据，“他会删数据”是所有人的共识，这就形成了部署阻力。&lt;/li&gt;
&lt;li&gt;数据的重要程度。C端数据和B端数据的重要性不同，零售、互联网、政府、金融行业的数据重要性也不同，对数据越重视的行业，对数据可靠性和业务连续性越敏感。个人电脑没有业务连续性，数据可靠性只有一个人在乎，但金融行业业务连续性可以直接引起广泛的社会关注，金融行业的数据可靠性就不可能说有问题。AI Ops的部署需要考虑系统重要程度来部署，不存在所有领域一起上的情况。&lt;/li&gt;
&lt;li&gt;管理体系。例如在金融系统中DBA有高权限，并有一套管理办法，那么AI DBA是不是应该也有对应的管理办法，才能去部署？什么异常登入库，什么异常登入后台，它要怎么申请权限，申请多久？在什么场景申请多大的权限？这都是未解决的问题。&lt;/li&gt;
&lt;li&gt;AI本身安全性。例如《STRATUS》这篇论文提到&lt;em&gt;prompt注入攻击&lt;/em&gt;，目前还没有有效的解决方案，例如你给AI注入“drop database”这个prompt它可能就执行了。但人基本没有这个问题，你跟DBA说drop database，它只会反问你你要干嘛。&lt;/li&gt;
&lt;li&gt;责任问题。运维工程不是“知识问题”，而是“责任问题”。运维的核心工作之一，就是在故障发生时，在有限的时间内，做出对系统不可逆**的决策，并对该动作负责。AI 可以取代“可形式化的操作”，但无法取代“必须承担后果的判断”，至少现在还没有&lt;/li&gt;
&lt;li&gt;充满噪音。运维是“开放系统”，不是封闭推理系统。数据库运行在一个极其复杂的环境中，而 AI 的推理前提是世界是可被文本描述的。但真实运维世界是世界是充满噪声、偶然性和非文档化行为的。&lt;/li&gt;
&lt;li&gt;情境压力。真实业务环境下包含恢复时间压力、组织和客户的情绪管理等。《GOOGLE SRE》这本书中描述了一个常见的恢复场景：客户在问什么时间恢复、领导在问为什么不切换、工程师在压力下收集各种信息和各种人打电话确认恢复手段。AI感受不到这个压力，前两个问题本质上不是技术问题，但不能不做答。真实场景下，当时的回答大概率马马虎虎。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以想象一下全自动AI运维真的发生，需要什么条件？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI不会干掉重要数据，至少绝大部分人对AI需要达成这种共识&lt;/li&gt;
&lt;li&gt;需要完善的管理办法，包括如何给AI权限，就如同如何给DBA权限一样&lt;/li&gt;
&lt;li&gt;解决AI本身被攻击的问题。不止是LLM，而是包含AI的整套IT体系&lt;/li&gt;
&lt;li&gt;不问责的运维文化（或者直接消灭运维也是一种思路）&lt;/li&gt;
&lt;li&gt;接受错误判断。对存在噪音和环境形成共识并容忍AI Ops的迭代周期&lt;/li&gt;
&lt;li&gt;如果长时间没有恢复或者影响面扩大，也不要人干预。因为如果一旦需要人干预，那么那个人还是运维（半自动AI Ops？）&lt;/li&gt;
&lt;li&gt;无压力恢复情境。指领导、客户、社会舆论不需要回复或者他们相信某AI的回复，这是人的转变不是IT系统的转变。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;AIOps、Agent的研究成果
 &lt;div id="aiopsagent的研究成果" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#aiopsagent%e7%9a%84%e7%a0%94%e7%a9%b6%e6%88%90%e6%9e%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;清华这个&lt;a href="https://github.com/TsinghuaDatabaseGroup/AIDB" target="_blank" rel="noreferrer"&gt;AIDB&lt;/a&gt;仓库的目录有许多AI4DB的论文，人是看不过来了，用notebooklm汇总了论文分类：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/46fe43a8cb1f.png" alt="image-20260118161019199" /&gt;&lt;/p&gt;
&lt;p&gt;再次为了减少讨论范围（主要是减少我的投入人力），我们主要看数据库诊断相关的内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AIOps在学术上有不错的进展&lt;/strong&gt;。AIOps研究通过将机器学习、强化学习及大语言模型集成于数据库管理，涵盖参数调优、索引建议、查询优化与故障诊断等关键任务，旨在构建具备自感知与自修复能力的“自动驾驶”数据库系统，在显著提升复杂工作负载性能与运维效率的同时，推动DBA从低效的手动干预转型为高层级的架构监管者。&lt;/p&gt;
&lt;p&gt;关于“DBA（数据库管理员）是否会被淘汰”的问题，目前的科研趋势和工业实践（尤其是自动驾驶数据库和大语言模型的应用）显示，DBA的角色正在经历一场从“手动操作者”向“高级管理者/监督者”的深刻转型，而非简单的被取代。&lt;strong&gt;DBA核心价值将转向管理AI运维策略、确保数据安全合规、以及处理AI无法解决的极端异常场景&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;另一篇&lt;a href="https://mp.weixin.qq.com/s/urqh4NZDmkXvDllBCCdZDA" target="_blank" rel="noreferrer"&gt;AI Ops前言综述&lt;/a&gt;的文章对Agent这样描述：&lt;/p&gt;
&lt;p&gt;“这说明AI Agent并非银弹，要应用Agent不只需要模型和agent层面的进步，还需要需要整个被运维系统具备足够的支持能力比如类似Kubernetes的声明式接口、良好的可观测性、可逆的操作设计。Stratus的初步实验证明了Agent在自动运维上的潜力，&lt;strong&gt;但距离生产部署在性能、可靠性和安全性上仍有巨大的问题&lt;/strong&gt;。”&lt;/p&gt;
&lt;p&gt;开发领域因为如火如荼的vibe coding，要明显比AI在运维领域的应用快很多。我也很想有个confirm、redo的运维遥控器，问题是现在确实没有。即使我们现在幻想有一天有vibe maintaining，应该也没有几个运维会打开yolo模式。&lt;/p&gt;

&lt;h2 class="relative group"&gt;DBA的价值
 &lt;div id="dba的价值" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dba%e7%9a%84%e4%bb%b7%e5%80%bc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;DBA的价值是拍板背锅侠吗
 &lt;div id="dba的价值是拍板背锅侠吗" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dba%e7%9a%84%e4%bb%b7%e5%80%bc%e6%98%af%e6%8b%8d%e6%9d%bf%e8%83%8c%e9%94%85%e4%be%a0%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;背书好像确实不能通过AI解决。那么DBA的价值就是拍板背锅侠吗？毕竟dba的知识远低于AI，只是AI不能拍板罢了。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;瞬时上下文&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“DBA 的知识远低于 AI”，这在通用知识（比如如何优化一个 SQL，或者某个配置参数的含义）上确实是事实。但 AI 缺少&lt;strong&gt;瞬时上下文（Runtime Context）&lt;/strong&gt;。 AI 知道数据库原理，但它不知道你公司双十一流量激增的瞬间，那个负载均衡器后面藏着的陈年历史债。DBA 拥有的是关于“这台特定机器、这个特定业务、这些特定人”的非结构化经验。在极端故障面前，&lt;strong&gt;AI 给出的是“概率最高的建议”，而 DBA 给出的是“在这个特定压力下，最能保住命的那个操作”。&lt;/strong&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;“混沌系统”的最后闸门&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;数据库是所有 IT 架构中最脆弱、最不容错的部分（代码坏了可以回滚，数据丢了公司可能就倒闭了）。AI 的逻辑是基于历史数据的推演。当出现从未见过的底层硬件坏道、极其罕见的分布式死锁，或者黑客的新型攻击手段时，AI 的“建议”往往会失效甚至造成二次伤害。“拍板”的核心不是“选哪个方案”，而是**“承担风险的对冲”&lt;strong&gt;。这种对&lt;/strong&gt;极端情况的掌控力**，是目前的AI无法提供的。&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;信任链&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DBA是信任链的维护者：例如让 AI 审计 AI，那么谁来审计 AI 的审计逻辑？在数据安全、合规和伦理层面，必须有一个&lt;strong&gt;拥有最高权限且可追责的人类&lt;/strong&gt;作为信任链的终点。&lt;/p&gt;
&lt;p&gt;我们反过来想，如果 DBA 真的只是“知识较少的拍板背锅侠”， 那么企业其实早就会把 DBA 的拍板权交给SRE或者架构委员会、甚至AI等等责任主体。但现实是在真正关键的时刻，企业仍然会把电话打给“那个人”。这说明问题从来不是“谁更聪明”，而是谁能在不确定性中，为组织承担后果。&lt;strong&gt;DBA 是数据库这个混沌系统中，最后一个拥有止损权、责任权和信任终结权的人类&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;那么拍板都是DBA说了算吗？显然不是。DBA 并不拥有“目标决策权”，而是拥有“风险否决权”——他们不能决定业务要不要冒险，但可以决定系统不能承受哪些冒险。在简单、低风险、可回滚的场景下，拍板往往由流程或系统自动完成；&lt;strong&gt;只有当决策进入高风险、不可逆、责任必须收敛的区间时，DBA 才会被推到台前&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;Postgres DBA的特殊性
 &lt;div id="postgres-dba的特殊性" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-dba%e7%9a%84%e7%89%b9%e6%ae%8a%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;针对 Postgres (PG) DBA 这个特定群体，其特殊性会更加显著。&lt;/p&gt;
&lt;p&gt;在现代技术组织中，DBA 并不天然拥有架构决策权，也不垄断索引或参数的制定。架构师可以设计方案，开发可以编写 SQL，AI 甚至可以给出看似完备的最佳实践建议。但这些决策大多发生在&lt;strong&gt;抽象层、设计层和概率层&lt;/strong&gt;，它们假设系统是可回滚、可重放、可修正的。&lt;/p&gt;
&lt;p&gt;Postgres 的特殊性在于，&lt;strong&gt;它将大量自由度交给使用者&lt;/strong&gt;，而这些自由度最终都会转化为真实系统中的&lt;strong&gt;长期副作用&lt;/strong&gt;：写放大、IO 模式变化、Vacuum 失衡、WAL 膨胀以及难以预测的性能退化。这些副作用无法在设计阶段完全预演，也无法被单一角色分包处理，更无法在事故发生后简单“撤回”。当系统进入不可暂停、不可重放的状态时，唯一仍需对整体结果负责的人，往往就是 DBA。&lt;/p&gt;
&lt;p&gt;因此，Postgres DBA 的价值不在于“替别人做决定”（当然也可以啦），而在于在所有决定已经发生之后，持续管理它们在现实世界中的后果。&lt;strong&gt;“架构师定义理想，开发实现功能，AI 预测未来；而 DBA 守护真实。”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个守护真实的能力是基于PG DBA拥有足够了解Postgres、足够了解系统真实环境、足够了解系统的历史和足够的即时上下文。在AI的时代，还需要再增加一个，足够了解AI。&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%ba%e4%bb%80%e4%b9%88%e8%bf%98%e8%a6%81%e5%ad%a6%e4%b9%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这两年听到读书无用论比以往多了许多，说这种话我一般都嗤之以鼻。借此机会好好盘一盘。&lt;/p&gt;
&lt;p&gt;数据库基础知识还有没有价值？答案是：&lt;strong&gt;价值更高了&lt;/strong&gt;。我们从解释权、主动学习和为什么我还在反复看经典来解读。&lt;/p&gt;
&lt;p&gt;1.问题的解释权&lt;/p&gt;
&lt;p&gt;基础知识让你做到三件事：&lt;/p&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;/ul&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;2.主动学习成为更稀缺的能力&lt;/p&gt;
&lt;p&gt;在 AI 时代，知识获取的“技术壁垒”趋近于 0。主动学习能力是稀缺的。为什么“主动学习”在 AI 时代反而更稀缺？这点很反直觉，但非常现实。AI 让“被动学习”极其舒服，随问随答、无需长期投入、不必承受认知不适。但是导致的结果是，越来越多的人停留在“即时满足层”，不愿意再去学习基础知识。当所有人都在倒退时，你发现你走的更快了。&lt;/p&gt;
&lt;p&gt;3.为什么还在反复看《The Internals of PostgreSQL》这种经典？&lt;/p&gt;
&lt;p&gt;技术人员需要看书，是因为书不是在给答案，而是在&lt;strong&gt;帮我建立一个可以反复运行、不断修正的认知模型&lt;/strong&gt;；而 AI 目前更擅长回答问题，而不是塑造这种模型。AI 很难成为这种“长期对话对象”，&lt;strong&gt;它的回答是不稳定的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;另一个方面，从认知经济学 + 信息论 + token 成本的视角来看书的价值。首先，你不用跟 AI battle 来 battle 去，battle 的真正成本不是钱，而是你的注意力和上下文维护能力。其次，书中的几十万字不仅不需要你输入大量的prompt，也不需要你付出过多的tokens。再次，这个书籍的知识经过了作者和读者的反复验证，是已压缩过的知识，是最容易学习的。所以，&lt;strong&gt;经典书籍 = 极低 token 成本下，获得高密度、被人类反复验证过的专注知识的压缩结果&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;4.学习AI本身&lt;/p&gt;
&lt;p&gt;这不需要我说了。&lt;/p&gt;
&lt;p&gt;跟AI的battle，让我得出一个有趣的关于“为什么还要看书”的结论：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 AI 时代，知识是廉价的，判断力才是昂贵的 =&amp;gt; 而判断力，来自于稳定、可校准的认知模型 =&amp;gt; 稳定的认知模型，本身是“长期高质量知识摄入”的副产品。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;另一个可以佐证读书有用论的一个现实证据是，我现在这篇文章依赖于我读过的一些书、论文、其他文章和资讯，如果没有这些，这篇文章不会与各位见面。&lt;/p&gt;

&lt;h2 class="relative group"&gt;为什么大家还爱看&amp;quot;人&amp;quot;写的文章
 &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%a4%a7%e5%ae%b6%e8%bf%98%e7%88%b1%e7%9c%8b%e4%ba%ba%e5%86%99%e7%9a%84%e6%96%87%e7%ab%a0" 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%81%8f%e7%88%b1%e6%bc%8f%e6%b4%9e%e7%9a%84%e5%bf%83%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;人类写的技术文章，难免漏洞百出，我自己看我去年写的运维经验2024，就可以找到很多漏洞。即便是前几天刚完成的运维经验2025，我也认为这篇文章是不完备的，跟AI写的东西差别很大。但是为什么读者还是喜欢这种漏洞百出的技术文章呢？&lt;/p&gt;
&lt;p&gt;原因可能是人类不是被“信息正确性”吸引，而是被“可共情的不完美心智痕迹”吸引。从《智力简史》这边书中可知，人类的智力模型本身就包含自我试错式的探险和观察别人的行为并映射自我这两种模型，这是一种学习过程，是人类与生俱来的。我们的大脑默认会扫描文本中的的犹豫、不确定、逻辑断裂、表达不顺、情绪泄漏等等，这些在 AI 文本中被系统性地忽略。在文字的漏洞和情绪中，读者可以感受到作者的思考和情绪，而AI只是给出了结果，读者几乎不会与AI有情绪共鸣。一般来说，只有真实经历过的人，才会留下这种“不好看”的痕迹。&lt;/p&gt;
&lt;p&gt;所以我相信很多人跟我一样，一眼纯AI的技术文章（不保证100%判断正确），一般不会有情绪读下去。但如果是人类认真写的，会认真读下去，去感受作者的感受，去抓他的不足或场景缺陷。&lt;/p&gt;
&lt;p&gt;当然，作者也可以喂一些提示词模仿之前文章的口吻或者故意留漏洞，不过我没有认真这么做过，简单试过生成了几篇，感觉情绪带入还是比较差。后面也不想再继续深入尝试了，再试下去意义也不大。&lt;/p&gt;

&lt;h3 class="relative group"&gt;白嫖大神的ATTENTION
 &lt;div id="白嫖大神的attention" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%99%bd%e5%ab%96%e5%a4%a7%e7%a5%9e%e7%9a%84attention" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;AI文章和大神文章的核心差异不是“写得好不好”，而是&lt;strong&gt;经济性问答、行业领先的Attention&lt;/strong&gt;的问题。大神写作是在替读者分配注意力，AI 写作是在避免遗漏任何可能相关的信息。这不是能力问题，而是目标函数不同。&lt;strong&gt;真正高价值的技术文章，不是告诉你所有正确答案， 而是替你挡住 80% 你现在不该关注的东西。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大神为什么敢“删”，AI 为什么不敢？因为他们为你的理解结果承担认知责任，AI不承担你学错、用错的后果。于是大神会刻意过滤那些目前不需要注意的细节。这种过滤，本身就是专家价值。对人类来说，学习的瓶颈不是信息不够，而是注意力有限、不知道先看哪里。&lt;strong&gt;大神的文章直接把结果给你对你说，你就看着这个。但你面对LLM的时候，你知道该找什么东西吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这并不是在否定 AI 文章的价值。AI 擅长的是“在你已经知道问题边界时，快速铺开信息空间”，而大神文章擅长的是“在你尚未建立判断框架时，替你先收缩问题空间”。前者适合查漏补缺、横向扩展，后者适合建立主干认知和关键直觉。真正高效的学习方式，并不是二选一，而是先借助大神完成 Attention 对齐，再利用 AI 在被限定的空间内做放大搜索。&lt;/p&gt;
&lt;p&gt;这不是在说AI的东西没有用，或者人类写的东西没用，而是&lt;strong&gt;各自有用&lt;/strong&gt;。&lt;/p&gt;

&lt;h2 class="relative group"&gt;AGI能解决所有问题吗？
 &lt;div id="agi能解决所有问题吗" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#agi%e8%83%bd%e8%a7%a3%e5%86%b3%e6%89%80%e6%9c%89%e9%97%ae%e9%a2%98%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;驳Musk
 &lt;div id="驳musk" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a9%b3musk" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;最近Musk又在画大饼，看完以后我并不赞同。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;共同富裕还是无用阶级？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;无用阶级是尤瓦尔在《未来简史》中的观点，他认为当AI的生产力超过普通人的时候，用AI干活会替代让普通人干活。这些人就成为了无用阶级。资源会愈发集中在少数精英和大公司手中，大部分人会失业，但是失业情况目前没有有效政策可以为之兜底。这个观点刚好与马斯克式的共同富裕有出入，马斯克认为当AGI实现时，所有人都不需要担心生存、教育、医疗，生产力高到政府会给大部分人兜底。我目前支持尤瓦尔的观点。其实从身边感知性统计也可以看出来，&lt;strong&gt;无用阶级的人数正在上升&lt;/strong&gt;。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;高生产力可以制造乌托邦吗？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个支持我不同意AGI乌托邦的理论来自于另一本书《进化心理学-择偶标准》。其中有一个观点令我印象深刻：&lt;em&gt;出于社会分工和生物培育良好后代的考虑，男性偏爱年轻、健康的女性，女性偏爱健康、有资源的男性&lt;/em&gt;。这个刻在我们基因里的默认筛选，导致了人是不会平等生活的，你不想成为被淘汰的那个。&lt;strong&gt;所以一个不攀比、没有竞争的、资源平等的乌托邦如果能够维持下去，生产力只是必要条件之一&lt;/strong&gt;，还有许多必须解决的社会问题容易被大众忽略。这里不是狭义的单指进化心理学，有些东西没有被仔细讨论，比如《黑猩猩政治》中的权力纷争，其实也应该被考虑。&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;卡尔霍恩的老鼠乌托邦实验&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1972 年，动物行为学家约翰·B·卡尔霍恩John B. Calhoun）设计并详细描述了一个著名的实验环境——“宇宙 25 号”。这是一个专门为老鼠打造的实验室“乌托邦”，几乎在每一个方面都力求完美：食物、水源和筑巢材料充足；居住环境定期清洁；没有捕食者威胁；温度通过风扇与供暖保持在 20℃至 31℃之间，稳定舒适。&lt;/p&gt;
&lt;p&gt;老鼠数量走向灭亡看起来有些疯癫，我选择只看过程部分：1)暴力增加 2)不再追求异性 3)同性行为增加 4)独处行为增加 5)男性爱打扮自己 6) 冷漠 等等。当然这个实验会有一些缺陷，从《智力简史》中描述的智力模型来看，老鼠和人的智力模型还差着一个灵长类动物，它不能代表人类社会。但是至少可以看出，&lt;strong&gt;乌托邦会引起新的社会问题，人们不会老老实实的过日子。&lt;/strong&gt;&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;基于经济学的社会&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从现代经济学的角度来看，AGI 是否能够实现“共同富裕式乌托邦”，可分为两种类型来看：保留现代经济和不保留现代经济。&lt;/p&gt;
&lt;p&gt;如果保留现代经济，AGI 可以被视为一种极端高效的“通用生产要素”。 它显著降低了知识生产、决策支持、组织协调和边际劳动成本，提高了全社会的生产率上限。在这一前提下，财富分配、公共服务供给和社会保障机制，仍然依托市场、价格信号、激励机制和制度约束运行。AGI 的作用更多体现在扩大“可分配蛋糕”的规模，而非自动解决分配问题。换言之**，**共同富裕依然是政治经济学问题，而不是技术问题，&lt;strong&gt;AGI 只能降低实现目标的成本，却无法替代制度设计&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;那么，如果不保留现代经济，而是试图绕过市场、价格与激励体系，直接依靠 AGI 实现某种“技术乌托邦”，是否可行？&lt;/p&gt;
&lt;p&gt;答案几乎可以确定是否定的。&lt;/p&gt;
&lt;p&gt;没有现代经济的乌托邦，在 20 世纪 60–70 年代已经被反复验证为失败。其根本原因并不在于当时“技术不够先进”，而在于信息与激励问题的结构性不可解：
&lt;strong&gt;即便拥有强大的集中式计算能力，也无法替代分散个体通过价格机制传递的偏好信息，更无法在长期内维持创新动力、责任约束和资源配置效率&lt;/strong&gt;。AGI 可以提高集中决策的计算能力，但无法消除“谁为决策负责、谁承担后果、谁拥有选择权”这一经济学基本问题。&lt;/p&gt;
&lt;p&gt;因此，AGI 并不是现代经济的替代者，而是现代经济框架下的放大器。任何脱离市场机制、激励结构和制度约束的“技术乌托邦”，无论是否引入 AGI，本质上都会重演历史上的失败路径，只是失败形式更加隐蔽、成本更高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生产力（包括 AGI 带来的智力提升）只是乌托邦所需条件之一，而且远远不是最关键的那一个。乌托邦不是算力问题，也不是智力问题，而是人类行为在制度约束下的稳定性问题。&lt;/strong&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="#ai%e8%a7%a3%e5%86%b3%e4%b8%8d%e4%ba%86%e6%89%80%e6%9c%89%e9%97%ae%e9%a2%98%e7%9a%84%e6%95%b0%e5%ad%a6%e5%9f%ba%e7%a1%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;以下抄自吴军的《数学之美》：&lt;/p&gt;
&lt;p&gt;“1900年，希尔伯特提出了许多问题，其中一个是：‘任意一个（多项式）不定方程，能否通过有限步的运算，判定它是否存在整数解’。如果对希尔伯特这个问题普遍答案是否定的，那么就说明很多数学问题其实上帝也不知道答案是否存在，因为不定方程求解问题还只是数学问题中很小的一部分。对于连答案存在与否都无法判定的问题，答案自然找不到的。正是希尔伯特对数学问题边界的思考，让图灵明白了计算的极限所在····马蒂亚塞维奇严格地证明了，除了极少数特例，在一般情况下，无法通过有限步的运算，判定一个不定方程是否存在整数解。&lt;strong&gt;这个问题的解决，对人类认知上的冲击，远比它在数学上的影响还要大···如果连解都不知道，就更不可能通过计算来解决他们了&lt;/strong&gt;”&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d18842a780aa.png" alt="image-20260120211018586" /&gt;&lt;/p&gt;
&lt;p&gt;“理性状态的图灵机可以解决的问题，只是有答案的问题中的一部分··很多工程上的问题并非人工智能问题···&lt;strong&gt;今天，我们所要担心的不是人工智能或计算机有多么强大，更不应该觉得他们无所不能，因为他们的边界已经清清楚楚地由数学的边界划定了&lt;/strong&gt;···世界上还有许多需要由人来解决的问题，如何利用好人工智能工具，更有效地解决属于人的问题，才是应该给予更多关注的。“&lt;/p&gt;
&lt;p&gt;（看吧，读书有用吧，直接给你讲明白，你大概率问不出来也拿不到这么通俗易懂的答案；看吧，关注硬核技术up有用吧，我帮你筛选了，快“点关注”&amp;#x2b50;）&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;p&gt;作为一个写技术文章的博主，写此类社会问题是比较少的。本来就想简单写写上一篇文章为什么有流量，结果为了解释这个现象有点把问题扩大化了&amp;#x1f613;。&lt;/p&gt;
&lt;p&gt;本篇的局限性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只讨论了DBA工作的很小一部分&amp;ndash;故障恢复，没有讨论其他工作的智能化问题。&lt;/li&gt;
&lt;li&gt;GPT太了解我了，看上去在PUA我。它确实说的很有道理，但我无法给它说的东西背书。这就有点套娃了，AI帮我确认AI不能背书，这个输出本来就无法背书。从我自己的视角来看，它的思路确实不错，金句频出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有些Ops场景当然是容易AI化的，但通过这篇文章的讨论，在故障恢复这个领域搞AI化，难度还是有的。&lt;strong&gt;我从来没有放弃用AI，也从来没有放弃用人脑&lt;/strong&gt;，我只是喜欢识别AI在什么场景下好用，什么场景下不好用，什么场景下用不了。这让文章的基调看起来对AI的未来很悲观，其实我的想法不是悲观。&lt;/p&gt;
&lt;p&gt;这篇文章的开头你可以看到 AI率是50%，实际上我还跟几个小伙伴讨论过类似问题，也包含自己的思考，所以这篇文章真正的智力比例是：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;AI率50%，其他人脑率10%，我的人脑率40%&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;所以这篇文章也算是”不放弃使用AI，也不放弃使用人脑“的一个典型案例了。&lt;/p&gt;
&lt;p&gt;最后用几个问题简单表面我的观点：&lt;/p&gt;
&lt;p&gt;为什么人们还是爱看人写的文章？心理偏好和注意力对齐&lt;/p&gt;
&lt;p&gt;读书有没有用（不只是书）？有用，而且比以往还有用（烂书比以往更没用，知识品味比以往更重要）&lt;/p&gt;
&lt;p&gt;AIOps会不会实现？会，但还要时间，而且并不容易。这需要学术突破和运维（含DBA）的思考和实践&lt;/p&gt;
&lt;p&gt;DBA会不会被替代？不会，跟软件开发者一样，会经历工作模式的改变，但不会消失&lt;/p&gt;
&lt;p&gt;留下来的DBA是哪些人？“懂DB又懂AI，不依赖AI，又不放弃判断的人”&lt;/p&gt;
&lt;p&gt;AGI会不会实现？会&lt;/p&gt;
&lt;p&gt;AGI会不会实现全面富裕？不会&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;如果想跟我讨论AI Ops或者文章中的问题，可以在各个PG群里找我，应该好找，或者给我留言也可以。&lt;/p&gt;
&lt;/blockquote&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://github.com/TsinghuaDatabaseGroup/AIDB" target="_blank" rel="noreferrer"&gt;https://github.com/TsinghuaDatabaseGroup/AIDB&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/urqh4NZDmkXvDllBCCdZDA" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/urqh4NZDmkXvDllBCCdZDA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Zhao, Y., et al. (2025). &amp;ldquo;STRATUS: A Multi-agent System for Autonomous Reliability Engineering of Modern Clouds&amp;rdquo;.Advances in Neural Information Processing Systems (NeurIPS)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zhuanlan.zhihu.com/p/631632685" target="_blank" rel="noreferrer"&gt;https://zhuanlan.zhihu.com/p/631632685&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;《数学之美》&lt;/p&gt;</content:encoded></item><item><title>pg数据库运维经验2025</title><link>https://lastdba.com/2026/01/11/pg%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%90%E7%BB%B4%E7%BB%8F%E9%AA%8C2025/</link><pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/01/11/pg%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%90%E7%BB%B4%E7%BB%8F%E9%AA%8C2025/</guid><description>&lt;p&gt;主要是技术性运维总结，主打通俗易懂和快速上手，同时也是对PG数据库运维的阶段性总结，希望对PGer有所帮助。&lt;/p&gt;
&lt;p&gt;历史的运维经验：&lt;a href="https://www.modb.pro/db/1876933230968975360" target="_blank" rel="noreferrer"&gt;pg数据库运维经验2024&lt;/a&gt;。注意，本篇不会包含历史的运维经验的内容。&lt;/p&gt;

&lt;h2 class="relative group"&gt;CPU
 &lt;div id="cpu" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cpu" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;SQL性能问题是PG异常处理根因中最多的，这包含SQL本身性能不好，索引一般、突发并发高、执行计划突变。对于postgres这种没有完善的绑定执行计划的方案的库来说，有一个DBA团队帮助设计数据模型、数据访问方式、索引、调整执行计划等显得尤为重要，实际上可以极大缓解CPU突然打满的问题。&lt;/p&gt;</description><content:encoded>&lt;p&gt;主要是技术性运维总结，主打通俗易懂和快速上手，同时也是对PG数据库运维的阶段性总结，希望对PGer有所帮助。&lt;/p&gt;
&lt;p&gt;历史的运维经验：&lt;a href="https://www.modb.pro/db/1876933230968975360" target="_blank" rel="noreferrer"&gt;pg数据库运维经验2024&lt;/a&gt;。注意，本篇不会包含历史的运维经验的内容。&lt;/p&gt;

&lt;h2 class="relative group"&gt;CPU
 &lt;div id="cpu" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cpu" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;SQL性能问题是PG异常处理根因中最多的，这包含SQL本身性能不好，索引一般、突发并发高、执行计划突变。对于postgres这种没有完善的绑定执行计划的方案的库来说，有一个DBA团队帮助设计数据模型、数据访问方式、索引、调整执行计划等显得尤为重要，实际上可以极大缓解CPU突然打满的问题。&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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;执行计划突变是cost-base优化器的老毛病，postgres也不会例外。&lt;/p&gt;

&lt;h4 class="relative group"&gt;DISTINCT不准确
 &lt;div id="distinct不准确" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#distinct%e4%b8%8d%e5%87%86%e7%a1%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1976119963471589376" target="_blank" rel="noreferrer"&gt;案例-从distinct不准确到DISTINCT的计算原理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;由于默认采样数最大是3w行，也就是说这种采样算法只要超过3w，即表比较大的时候，预估distinct很可能偏小。注意这里的数据不能有太多唯一值。&lt;/p&gt;
&lt;p&gt;测试一张表不同采样数的差异：&lt;/p&gt;
&lt;p&gt;表有reltuples=8亿，relpages=2kw，size=175GB，真实的某字段distinct 1亿&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;target statistics&lt;/th&gt;
 &lt;th&gt;pages采样比例（1）&lt;/th&gt;
 &lt;th&gt;tuples采样比例（1）&lt;/th&gt;
 &lt;th&gt;n_distinct&lt;/th&gt;
 &lt;th&gt;执行时间&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;50&lt;/td&gt;
 &lt;td&gt;0.00075&lt;/td&gt;
 &lt;td&gt;0.00001875&lt;/td&gt;
 &lt;td&gt;6w&lt;/td&gt;
 &lt;td&gt;2秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;100&lt;/td&gt;
 &lt;td&gt;0.0015&lt;/td&gt;
 &lt;td&gt;0.0000375&lt;/td&gt;
 &lt;td&gt;11w&lt;/td&gt;
 &lt;td&gt;5秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1000&lt;/td&gt;
 &lt;td&gt;0.015&lt;/td&gt;
 &lt;td&gt;0.000375&lt;/td&gt;
 &lt;td&gt;103w&lt;/td&gt;
 &lt;td&gt;58秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3000&lt;/td&gt;
 &lt;td&gt;0.045&lt;/td&gt;
 &lt;td&gt;0.001125&lt;/td&gt;
 &lt;td&gt;268w&lt;/td&gt;
 &lt;td&gt;3分01秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10000&lt;/td&gt;
 &lt;td&gt;0.15&lt;/td&gt;
 &lt;td&gt;0.00375&lt;/td&gt;
 &lt;td&gt;675w&lt;/td&gt;
 &lt;td&gt;7分21秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（target statistics 最大值10000）&lt;/p&gt;
&lt;p&gt;可以粗糙的总结：n_distinct和analyze的执行时间随采样数量成倍增长。&lt;/p&gt;
&lt;p&gt;n_distinct随采样数量增长，pages和tuples却一直都很准确。&lt;/p&gt;

&lt;h4 class="relative group"&gt;generic plan的干扰
 &lt;div id="generic-plan的干扰" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#generic-plan%e7%9a%84%e5%b9%b2%e6%89%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg的执行计划要考虑generic plan。generic plan与传参是无关的，它用一些默认值计算cost，并与前五次计划的代价进行对比，谁小用谁。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1964312913808732160" target="_blank" rel="noreferrer"&gt;案例-添加索引性能下降和generic plan&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一、generic plan预估不准的问题分类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为有5次机制对比，所以generic plan的问题可以分为2种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;前5次SQL的执行没有普遍性。跟前5次执行计划相关性大，依赖数据倾斜和前5次参数是否具有普遍性。&lt;/li&gt;
&lt;li&gt;generic plan本身有问题。generic plan因为数据倾斜或数据均衡但无法准确计算选择率，导致generic plan本身执行效率低下&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;二、解决方案参考&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;generic plan问题在分区表上可能会出现，分区键是连续的，扫描所有分区建选择率应该为1，但generic plan为0.05，很可能导致走“全索引”扫描这种场景。&lt;/p&gt;
&lt;p&gt;所以在优化的时候需要考虑更多：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要建太多索引迷惑优化器&lt;/li&gt;
&lt;li&gt;排除generic plan的干扰。用&lt;code&gt;EXECUTE&lt;/code&gt;真实跑6次&lt;/li&gt;
&lt;li&gt;会话级别&lt;code&gt;set plan_cache_mode='force_generic_plan'&lt;/code&gt;; or &lt;code&gt;set plan_cache_mode='force_custom_plan';&lt;/code&gt;对比执行计划；或者在pg16+用&lt;code&gt;explain (GENERIC_PLAN)&lt;/code&gt;对比执行计划&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--prepare/excute
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PREPARE sql1(text) AS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SELECT COUNT(*) FROM LZL where a=$1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXECUTE sql1(&amp;#39;zzz&amp;#39;); --跑6次再说
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXPLAIN EXECUTE sql1(&amp;#39;zzz&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;select * from pg_prepared_statements --查看prepare语句信息，只能看当前会话
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--对比执行计划，设置会话参数后执行EXPLAIN EXECUTE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set plan_cache_mode=&amp;#39;force_generic_plan&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set plan_cache_mode=&amp;#39;force_custom_plan&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--直接查看genetic plan,16+
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;explain (GENERIC_PLAN) xx &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;行锁导致的LWLock:Lockmanager
 &lt;div id="行锁导致的lwlocklockmanager" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e5%af%bc%e8%87%b4%e7%9a%84lwlocklockmanager" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LWLock Lockmanager问题一般发生在分区表上，高并发没有分区键的SQL容易发生。而今年又发现一个新的场景：&lt;a href="https://www.modb.pro/db/1995089823380627456" target="_blank" rel="noreferrer"&gt;行锁导致的LWLock:Lockmanager&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这不算一个很大的问题，因为更新同一行会阻塞是众所周知的。只是没有测试前我也没有想到更新同一行也会产生LWLock:Lockmanager。不算特别有价值的案例，在观察等待事件有LWLock:Lockmanager时考虑行锁即可。&lt;/p&gt;

&lt;h3 class="relative group"&gt;idle连接数
 &lt;div id="idle连接数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#idle%e8%bf%9e%e6%8e%a5%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PostgreSQL的性能基本随着大版本提升而稳定提升。其中PG14对快照的获取和维护所有backend的事务信息都做了&lt;a href="https://liuzhilong.blog.csdn.net/article/details/130783036" target="_blank" rel="noreferrer"&gt;大幅优化&lt;/a&gt;，使得14对多idle connection的提升明显：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/88df744da257.jpg" alt="performance-impact-of-idle-connections-48active-prepost.png" /&gt;（https://techcommunity.microsoft.com/blog/adforpostgresql/improving-postgres-connection-scalability-snapshots/1806462）&lt;/p&gt;
&lt;p&gt;但，这不代表14以后就不需要关注idle连接数了，它仍然会消耗backend事务维护成本、上下文切换、使内存碎片化等问题，导致数据库的idle连接数越多性能越差。&lt;/p&gt;
&lt;p&gt;一般业务连接本身是有轮询和保活的，保持一定的idle是为了不让每个请求都新建连接，那样消耗就大了去了。一般小库是不太需要关注连接数（只要别太离谱），因为CPU买的不多，系统也没那么重要，而且扩容比较容易。但是大库又不一样了。CPU数就是主机资源上限，再加也加不上去了。大库本身idle connection就很多，再增加空闲连接不一定会增加系统的吞吐量，特别是CPU已经不太够时，增加idle连接会起反向效果。&lt;/p&gt;
&lt;p&gt;以PG15压测经验来看，以5k idle为基线，上1w个idle时，idle的维护会多使用2-5个vCPU，上2w个idle时，多使用5-10个vCPU。大致情况是这样。&lt;/p&gt;

&lt;h3 class="relative group"&gt;idle in transaction
 &lt;div id="idle-in-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="#idle-in-transaction" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;去年狠狠把长事务批判了一遍，因为长事务对PG的影响要比其他库（oracle、mysql等）要大。但这问题不大，做好告警和运维，长事务问题是可解决的。&lt;/p&gt;
&lt;p&gt;在监控会话状态时，一般都要查看会话状态，比如active代表正在运行，代表在跑SQL，idle in transaction代表事务在空闲状态，代表事务没有在跑SQL也没有提交。所有的&lt;a href="https://www.postgresql.org/docs/18/monitoring-stats.html#MONITORING-PG-STAT-ACTIVITY-VIEW" target="_blank" rel="noreferrer"&gt;pg_stat_activity.state如下，pg15&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;Current overall state of this backend. Possible values are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;active&lt;/code&gt;: The backend is executing a query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;idle&lt;/code&gt;: The backend is waiting for a new client command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;idle in transaction&lt;/code&gt;: The backend is in a transaction, but is not currently executing a query.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;idle in transaction (aborted)&lt;/code&gt;: This state is similar to &lt;code&gt;idle in transaction&lt;/code&gt;, except one of the statements in the transaction caused an error.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fastpath function call&lt;/code&gt;: The backend is executing a fast-path function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled&lt;/code&gt;: This state is reported if &lt;a href="https://www.postgresql.org/docs/15/runtime-config-statistics.html#GUC-TRACK-ACTIVITIES" target="_blank" rel="noreferrer"&gt;track_activities&lt;/a&gt; is disabled in this backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见的state只有&lt;code&gt;active&lt;/code&gt;,&lt;code&gt;idle&lt;/code&gt;,&lt;code&gt;idle in transaction&lt;/code&gt;,&lt;code&gt;idle in transaction (aborted)&lt;/code&gt;。&lt;code&gt;idle in transaction&lt;/code&gt;有一个误区是，它只代表当前时间没有运行sql，没有提交事务，不代表这个事务空闲了很久。不能通过事务&lt;code&gt;xact_start&lt;/code&gt; +&lt;code&gt;idle in transaction&lt;/code&gt;判断事务多久没跑，而应该通过&lt;code&gt;state_change&lt;/code&gt; +&lt;code&gt;idle in transaction&lt;/code&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" 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="#%e5%86%85%e5%ad%98%e9%97%ae%e9%a2%98%e5%92%8c%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;


&lt;img src="https://lastdba.com/img/csdn/1fdf8b816eb0.png" alt="image.png" /&gt;&lt;/p&gt;
&lt;p&gt;pg内存问题相关wchan：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c2d5d422e6f9.png" alt="image.png" /&gt;&lt;/p&gt;
&lt;p&gt;大页对内存碎片、CG内直接内存回收都非常好的效果。&lt;/p&gt;
&lt;p&gt;大页实际效果看压测：https://docs.paic.com.cn/#/post/84479375&lt;/p&gt;
&lt;p&gt;大页八股文理论效果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;减少TLB的压力&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;减少pagetable在主内存上的大小&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大页在物理上是连续的。连续的物理内存访问比不连续的物理内存访问更优&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当使用大页时，page是直接映射的，不会使用多级的pte条目&lt;/p&gt;
&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;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/Linux%E5%86%85%E5%AD%98%E8%BF%9B%E9%98%B6.md" target="_blank" rel="noreferrer"&gt;Linux内存进阶&lt;/a&gt;。总之要记住如下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;优先排除os层问题再解决pg实例层问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大页有神奇的效果，但极少数情况仍没有效果&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;很多小伙伴不会关注pgpgin/pgpgout/pgfree，甚至不会关心pgscank/pgscand，只会看cpu、内存用了多少。这对运维pg库来说是不够的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有良好的运维体系pg的内存会很不稳定&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&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="#%e5%80%bc%e5%be%97%e6%b3%a8%e6%84%8f%e7%9a%84cgroup%e7%9f%a5%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;cgroup的知识也不少，参考之前的文章吧，这里做个简单总结。&lt;/p&gt;
&lt;p&gt;cgroup v1有自身的缺陷：&lt;/p&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;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%9c%aa%e8%a7%a3%e4%b9%8b%e8%b0%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;大页确实解决了很多问题，但不能解决所有内存问题。不能解决的这部分问题待研究，希望26年可以弄明白。&lt;/p&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="#%e5%85%b3%e6%b3%a8os" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 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="#%e5%85%b3%e6%b3%a8os%e7%9a%84%e4%b8%80%e5%88%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;学习开源库需要了解操作系统&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;（这句话已忘记出处）&lt;/p&gt;
&lt;p&gt;想要运维好Postgres，了解OS的原理是十分重要的。Postres数据库就是构建在OS（特别是linux）之上，linux提供什么它用什么，postgres是linux的生态。所以想要深入理解运行原理，得先了解操作系统原理。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;优先排除os层问题再解决pg实例层问题&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;（这句话是我说的）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一、CPU&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为postgres还用不了NUMA，无论是主机资源全给，还是CGROUP（or pod）管理cpu，都不太需要深入到操作系统层CPU原理。CPU问题看看SQL或者PG的堆栈基本够了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二、内存&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;内存参考内存章节。内存问题是需要深入到OS层的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三、进程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从操作系统查看PG进程的状态非常重要，包括但不限于要查看D、wchan、RSS、SYSCALL&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;四、主机状态和日志&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;监控主机状态、包括主机层CPU、内存、IO、网络、日志。非常重要。&lt;/p&gt;
&lt;p&gt;难以想象“an I/O error occured while sending to the backend”这种网络IO的模糊告警跟底层存储是相关的。除了查看/var/log/message，pg层看不出来有什么。当然这个报错有可能不是这个原因，请勿曲解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;五、其他&lt;/strong&gt;&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="#%e7%89%a9%e7%90%86%e8%af%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;postgres&lt;em&gt;本身不直接暴露“真正的物理磁盘读”（Physical Disk Read）指标&lt;/em&gt;。pg_stat中的各种reads（比如&lt;code&gt;pg_stat_database.blks_read&lt;/code&gt; ）都是从os cache中读。&lt;/p&gt;
&lt;p&gt;那怎么监控物理读？&lt;/p&gt;
&lt;p&gt;reads或者buffer allocation指标都是辅助策略，最好的办法还是监控OS。&lt;/p&gt;
&lt;p&gt;os是postgres的生态，绝对不要单看数据库。数据库层监控不到物理读不值得PGer shame，有方案就没问题。&lt;/p&gt;
&lt;p&gt;监控iostat以及各种五花八门的磁盘监控指标。对于云环境来说，os层的监控体系已经十分成熟了，不要浪费基于云的可观测性。&lt;/p&gt;

&lt;h2 class="relative group"&gt;autovacuum
 &lt;div id="autovacuum" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#autovacuum" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;监控autovacuum process的SQL参考&lt;a href="https://gitlab.com/postgres-ai/postgresql-consulting/postgres-howtos/-/blob/main/0067_autovacuum_queue_and_progress.md" target="_blank" rel="noreferrer"&gt;sql autovacuum_queue_and_progress&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;大库的autovacuum freeze
 &lt;div id="大库的autovacuum-freeze" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e5%ba%93%e7%9a%84autovacuum-freeze" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;只要把参数、监控、告警配好，autovacuum freeze在绝大部分库中，都是不太需要关注的。&lt;/p&gt;
&lt;p&gt;但是，在一些事务并发超高、数据特别大的库，仍然不可以忽略。因为autovacuum prevent wraparound可能随时都在跑，此时至少要关注如下两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;年龄告警，及时处理并尽量避免下一次告警。不要出现快死到临头了才来着急挽救（加速方案需要看版本，比如&lt;code&gt;INDEX_CLEANUP OFF&lt;/code&gt;,&lt;code&gt;BUFFER_USAGE_LIMIT&lt;/code&gt;的调整）&lt;/li&gt;
&lt;li&gt;对内存（特别是cache）的冲击。如果autovacuum跑个不停，库又特别大，对cache也有一定冲击，对内存是有影响的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理和参数参考howstos这个图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c216c393371f.jpg" alt="Wraparound and freeze" /&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%a4%a7%e8%a1%a8%e8%b7%91%e4%b8%8d%e5%8a%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;大表指上百GB的表，一般有许多索引和死元组才会“跑不动”。&lt;/p&gt;
&lt;p&gt;跑不动的主要原因是：(auto)vacuum会根据死元组，一条条的去索引上清理死索引元组。一般大表的(auto)vacuum就慢在这里，一般可以看到这个大表的死元组也比较多。更恐怖的是，这可能导致(auto)vacuum的运行速度慢于死元组生成速度，也就是(auto)vacuum永远跑不完，无限膨胀。&lt;/p&gt;
&lt;p&gt;对于大表跑不完的场景经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一表，死元组数&lt;em&gt;基本&lt;/em&gt;与执行时间成正比&lt;/li&gt;
&lt;li&gt;从autovacuum日志中的user time，elapsed time可以观察使用cpu时间和执行时间，即可大致推测delay sleep时间&lt;/li&gt;
&lt;li&gt;关闭autovacuum cost-based delay，可以减少3倍执行时间（与索引大小相关，属于来源：200GB表，280GB索引）&lt;/li&gt;
&lt;li&gt;调整某表的autovacuum cost-based delay含义是让autovacuum跑这个表更少的休息，会在更短的时间内消耗更多CPU以及扫描表时的io&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如何加速？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;repack。repack属于釜底抽薪型，可以快速重建表，在应急时可以使用。但repack毕竟是cli工具，每次去跑比较麻烦。&lt;/li&gt;
&lt;li&gt;调整autovacuum的 cost-based delay参数。可1.调大cost limit &lt;code&gt;alter table t1 SET (autovacuum_vacuum_cost_limit=1000);&lt;/code&gt; ,或者2.直接关闭delay睡眠时间&lt;code&gt;alter table t1 SET (autovacuum_vacuum_cost_delay=0);&lt;/code&gt;。建议仅对autovacuum跑不过来的表调整。&lt;/li&gt;
&lt;li&gt;删除不必要的索引。扫描索引并更新索引条目的时间是最久的，删除不必要的索引当然有效&lt;/li&gt;
&lt;li&gt;分区表。推荐分区大小不大于10GB；&lt;em&gt;改造为分区表是最好的方案&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;删除updated_time字段索引以利用HOT，以减少膨胀率&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;checkpoint和bgwriter
 &lt;div id="checkpoint和bgwriter" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#checkpoint%e5%92%8cbgwriter" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;checkpointer不仅要打检查点，跟实例恢复的时间相关，它还会做刷脏。而bgwriter只是做刷脏。从pg 17开始一些指标转移到&lt;code&gt;pg_stat_checkpointer&lt;/code&gt; ，这里以pg 17-为例，基本只看&lt;code&gt;pg_stat_bgwriter&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;一、checkpoint间隔&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指标&lt;code&gt;checkpoints_timed&lt;/code&gt;：对应&lt;code&gt;checkpoint_timeout&lt;/code&gt;参数&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;checkpoints_req&lt;/code&gt;：对应&lt;code&gt;max_wal_size&lt;/code&gt;参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐以&lt;code&gt;checkpoint_timeout&lt;/code&gt;为基本的checkpoint间隔，如果出现c&lt;code&gt;heckpoints_req&lt;/code&gt;，应该将&lt;code&gt;max_wal_size&lt;/code&gt;调大，并配合调整刷脏参数。有FPI时也应该检查这两个指标表现。&lt;/p&gt;
&lt;p&gt;二、刷脏指标&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指标&lt;code&gt;buffers_checkpoint&lt;/code&gt;：checkpointer刷脏数&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;buffers_clean&lt;/code&gt;：bgwriter刷脏数&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;buffers_backend&lt;/code&gt;：backend刷脏数，这应该尽量少的出现，出现说明bgwriter刷脏不够激进&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;buffers_backend_fsync&lt;/code&gt;：意义不明&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;刷脏调参目标以刷脏优先级为目标，&lt;strong&gt;刷脏优先级为：bgwriter刷脏 &amp;gt; checkpointer刷脏 &amp;gt; backend刷脏&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;checkpointer虽然可以顺手刷脏，但是checkpointer不好控制刷脏速度，即可能出现checkpointer会引起IO突刺的情况。所以bgwriter的刷脏优先级应高于checkpointer。backend刷脏自不必多说，这是backend触发的刷脏，应尽量减少这种情况。&lt;/p&gt;
&lt;p&gt;三、bgwriter刷脏参数&lt;/p&gt;
&lt;p&gt;bgwriter是通过“写多少停一下然后继续写的方式”来控制刷脏速度的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数&lt;code&gt;bgwriter_delay&lt;/code&gt;：停多久&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;bgwriter_lru_maxpages&lt;/code&gt;：一次最多写多少&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;bgwriter_lru_multiplier&lt;/code&gt;：一次写多少=(近期buffer allocate* lru_multiplier)，但不大于lru_maxpages&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;bgwriter_flush_after&lt;/code&gt;：刷多少后做fsync&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;pg_buffers_alloc&lt;/code&gt;：可以代表共享内存buffer的分配量。（allocate是产生了实质的换入的，可以一定程度上代表内存换入pgpgin）。&lt;/li&gt;
&lt;li&gt;指标&lt;code&gt;maxwritten_clean&lt;/code&gt;：到达&lt;code&gt;bgwriter_lru_maxpages&lt;/code&gt;的次数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;默认的bgwriter刷脏逻辑：&lt;strong&gt;一次刷（新buffers数*2，但不大于100个dirty buffers），delay 200ms，每刷64个buffers后 fsync&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;平时的一周期刷脏量跟近期的buffer allocation多少和&lt;code&gt;bgwriter_lru_multiplier&lt;/code&gt;参数相关，而在高峰期时buffer allocation一般是比较高的，所以高峰期一般会触达&lt;code&gt;bgwriter_lru_maxpages&lt;/code&gt;上限。所以可以这样理解：&lt;strong&gt;bgwriter_lru_maxpages用于限制高峰期刷脏上限；bgwriter_lru_multiplier用于控制低峰期不要频繁刷脏&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;四、刷脏参数参考&lt;/p&gt;
&lt;p&gt;默认最大bgwriter刷脏=100*5*8k=3.9M/s。默认bgwriter刷脏参数肯定是偏小的，如果需要调大的话应该结合shared_buffer的大小和负载来进行调整。&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;#读写比2:8，负载较高&lt;/span&gt;
&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;40GB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;checkpoint_timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;20min;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_wal_size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;80GB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bgwriter_delay&lt;span style="color:#f92672"&gt;=&lt;/span&gt;20ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bgwriter_lru_maxpages&lt;span style="color:#f92672"&gt;=&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;bgwriter_lru_multiplier&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;看情况再进行下一步调整。&lt;/p&gt;
&lt;p&gt;至于效果，从实际的经验来看，不要期待单独调整bgwriter可以有好的效果。甚至bgwriter调整的过于激进可能会有反向效果。&lt;/p&gt;
&lt;p&gt;所以，&lt;strong&gt;你的库没有明确定位到是checkpoint刷脏突刺或者其他刷脏的问题，那就不要动这个&lt;/strong&gt;。仅推荐核心大库、并发高的库，在调整其他东西的时候（比如迁移时、调shared buffer时等）一并调整刷脏，当成附属调优策略。&lt;/p&gt;
&lt;p&gt;五、刷脏参数总结&lt;/p&gt;
&lt;p&gt;bgwriter刷脏可以总结为“三难”：&lt;/p&gt;
&lt;p&gt;“难懂、难调、难有效果”&lt;/p&gt;

&lt;h2 class="relative group"&gt;DB4AI
 &lt;div id="db4ai" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#db4ai" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#ai%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e4%bf%a1%e6%81%af%e5%86%99%e5%85%a5%e6%95%b0%e6%8d%ae%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;AI的应用已经在开发层面已经应用得非常广泛，其中一个场景是调用AI的任务会写进数据库，任务调用可能是瞬间极高的，而写入数据库的请求可能是没有并发控制的，所以会导致数据库的cpu或者其他资源使用率飙升。&lt;/p&gt;
&lt;p&gt;这是一个AI时代背景下的一个新的数据库故障场景，careful。&lt;/p&gt;

&lt;h3 class="relative group"&gt;vector hnsw
 &lt;div id="vector-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="#vector-hnsw" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;参考资料：https://postgresql.us/events/pgconfnyc2024/sessions/session/1862/slides/172/pgvector_best_practices_pgconfnyc2024.pdf&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%e6%9e%84%e5%bb%ba%e5%8a%a0%e9%80%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;HNSW索引在构建的时候可以非常慢，百万行数据可以慢到以小时计。&lt;/p&gt;
&lt;p&gt;影响HNSW索引构建速度的，除了套餐的内存（和cpu）以外，还有索引构建参数，例如：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;maintenance_work_mem&lt;span style="color:#f92672"&gt;=&lt;/span&gt;3g
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_parallel_maintenance_workers&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;m&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;ef_construction&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;创建HNSW可能非常折磨人，我们可以有以下手段加速创建索引：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在数据写入前建索引，其实是一个选择。虽然initial整体时间更慢，但是开发可接受慢一点，但接收不了建1个小时的索引&lt;/li&gt;
&lt;li&gt;在数据写入后建索引优化&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SET maintenance_work_mem = '8GB'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SET max_parallel_maintenance_workers = 8&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;after建索引需要注意内存问题，跟套餐内存，空闲内存强相关&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;注意&lt;code&gt;maintenance_work_mem &lt;/code&gt;是可以起到保护OS mem的作用，如果&lt;code&gt;maintenance_work_mem&lt;/code&gt;超过了OS 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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;53200&lt;/span&gt;: could &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; resize shared memory segment &lt;span style="color:#e6db74"&gt;&amp;#34;/PostgreSQL.1390017142&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6439348672&lt;/span&gt; bytes: Cannot &lt;span style="color:#66d9ef"&gt;allocate&lt;/span&gt; memory
&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;: dsm_impl_posix, dsm_impl.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;314&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;maintenance_work_mem&lt;/code&gt;会有info提示（达到一定时间）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;NOTICE: &lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;: hnsw graph &lt;span style="color:#66d9ef"&gt;no&lt;/span&gt; longer fits &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; maintenance_work_mem &lt;span style="color:#66d9ef"&gt;after&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;886990&lt;/span&gt; tuples
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: Building will take significantly &lt;span style="color:#66d9ef"&gt;more&lt;/span&gt; time.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: Increase maintenance_work_mem &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; speed up builds.
&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;: InsertTuple, hnswbuild.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;525&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;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%e6%9f%a5%e8%af%a2%e9%80%9f%e5%ba%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;查询的召回率和性能之间需要做平衡，通过调整&lt;code&gt;ef_search&lt;/code&gt;参数实现。&lt;/p&gt;
&lt;p&gt;查询时除了&lt;code&gt;ef_search&lt;/code&gt;参数影响较大外，还有一个影响查询返回速度的因素：&lt;strong&gt;HNSW索引是否缓存在内中&lt;/strong&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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; image_id, applyNo, feature_vector &lt;span style="color:#f92672"&gt;&amp;lt;-&amp;gt;&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; vectorsit
&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; image_features_test2
&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; distance
&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; &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; 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;11852&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11865&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;74&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;10&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;82193&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;073&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;82193&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;185&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;10&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1796&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:#ae81ff"&gt;9309&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I&lt;span style="color:#f92672"&gt;/&lt;/span&gt;O Timings: shared&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;local&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:#ae81ff"&gt;82108&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;559&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; &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;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;02&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;32&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;009&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; Buffers: shared hit&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; test_0 (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;23&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;1360&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&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;007&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:#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; Buffers: shared hit&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_feature_hnsw &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; image_features_test2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11852&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;78&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1292546&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;989705&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;82193&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;071&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;82193&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;179&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;10&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:#66d9ef"&gt;Order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;By&lt;/span&gt;: (feature_vector &lt;span style="color:#f92672"&gt;&amp;lt;-&amp;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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1796&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:#ae81ff"&gt;9309&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I&lt;span style="color:#f92672"&gt;/&lt;/span&gt;O Timings: shared&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;local&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:#ae81ff"&gt;82108&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;559&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;130&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;82193&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;279&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;索引在内存中：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; 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;11852&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11865&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;74&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;10&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;240&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;350&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;10&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11105&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; &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;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;02&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;32&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;007&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:#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; Buffers: shared hit&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; test_0 (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;23&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;1360&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&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;007&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;007&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; Buffers: shared hit&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_feature_hnsw &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; image_features_test2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11852&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;78&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1292546&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;989705&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;239&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;344&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;10&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:#66d9ef"&gt;Order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;By&lt;/span&gt;: (feature_vector &lt;span style="color:#f92672"&gt;&amp;lt;-&amp;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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;11105&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;093&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;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;392&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;同一个索引，同一个执行计划，&lt;strong&gt;索引是否在内存中的性能差距是82193.279/20.392=4000倍！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个差距是不可忽略的，关注HNSW索引性能时，一定要观测HNSW索引是否在内存中。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;--buffercache查看hnsw是否在shared buffer中缓存
&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;c&lt;/span&gt;.relname, pg_size_pretty(&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;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; buffered, round(&lt;span style="color:#ae81ff"&gt;100&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;count&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;SELECT&lt;/span&gt; setting &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_settings &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;shared_buffers&amp;#39;&lt;/span&gt;)::integer, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; buffer_percent, round(&lt;span style="color:#ae81ff"&gt;100&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;count&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;8192&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; pg_table_size(&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.oid), &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; percent_of_relation &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INNER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_buffercache b &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; b.relfilenode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.relfilenode &lt;span style="color:#66d9ef"&gt;INNER&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; (b.reldatabase &lt;span style="color:#f92672"&gt;=&lt;/span&gt; d.oid &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; d.datname &lt;span style="color:#f92672"&gt;=&lt;/span&gt; current_database()) &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;.oid, &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.relname &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;3&lt;/span&gt; &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;10&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; buffered &lt;span style="color:#f92672"&gt;|&lt;/span&gt; buffer_percent &lt;span style="color:#f92672"&gt;|&lt;/span&gt; percent_of_relation 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------------------------+------------+----------------+---------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_feature_hnsw_1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2117&lt;/span&gt; MB &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;91&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;44&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; idx_feature_hnsw &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;78&lt;/span&gt; MB &lt;span style="color:#f92672"&gt;|&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:#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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_inherits_parent_index &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt; bytes &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; &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;0&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="#%e4%b8%9a%e5%8a%a1%e5%8f%91%e7%89%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;ddl的技巧
 &lt;div id="ddl的技巧" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ddl%e7%9a%84%e6%8a%80%e5%b7%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;online ddl工具pg-osc、pg_migrate都不支持分区表，而且工具还有一些其他问题，真实使用比较困难。所以DDL的技巧还算比较有用，可以降低锁级别、提前识别阻塞等以减少DDL阻塞和重写带来的风险。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5f610ac9b703.png" alt="picddl" /&gt;&lt;/p&gt;
&lt;p&gt;理解这个图的关键点：&lt;/p&gt;
&lt;p&gt;变更前的注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;确保表上没有长事务——长事务会长期持有表上的锁，长事务在pg中是危害这是共识，应先处理长事务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确保表上没有autovacuum (to prevent wraparound)——autovacuum一般不会阻塞SQL，但做&lt;code&gt;to prevent wraparound&lt;/code&gt;的&lt;a href="https://www.postgresql.org/docs/18/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND" target="_blank" rel="noreferrer"&gt;除外&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Autovacuum workers generally don&amp;rsquo;t block other commands. If a process attempts to acquire a lock that conflicts with the &lt;code&gt;SHARE UPDATE EXCLUSIVE&lt;/code&gt; lock held by autovacuum, lock acquisition will interrupt the autovacuum. However, if the autovacuum is running to prevent transaction ID wraparound (i.e., the autovacuum query name in the &lt;code&gt;pg_stat_activity&lt;/code&gt; view ends with &lt;code&gt;(to prevent wraparound)&lt;/code&gt;), the autovacuum is not automatically interrupted.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lock_timeout=2000&lt;/code&gt;——即拿不到锁超过2s就不拿了，以免引发大面积阻塞&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;字段小改大的特例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段小改大一般不会重写表，但有几个例外。特别要注意int-&amp;gt;bigint（常见主键字段）, char(n)-&amp;gt;char(m)）&lt;/li&gt;
&lt;li&gt;分区表索引。分区表字段小改大不会重写表，但会重建索引，而分区表重建索引一般都非常慢，很可能造成长期8级锁阻塞。这个特性是普通表没有的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;修改字段类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本都会重写表，除了一些类型等价，或者属于另一种小改大的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DDL降低锁级别的注意点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;索引用CIC，分区不支持就子表CIC（记得attach index）&lt;/li&gt;
&lt;li&gt;CIC执行分了好几个阶段。其中2、3阶段会获取share锁，阻塞dml（官方文档只说了SHARE UPDATE EXCL.（不等DML），CIC不是单纯的显式锁）&lt;/li&gt;
&lt;li&gt;添加主键用using index，分区不支持就利用“子表加主键+父表添加主键可合并已存在的子表主键的特性”&lt;/li&gt;
&lt;li&gt;约束用validate constraint&lt;/li&gt;
&lt;li&gt;17以前不支持not null validate，可以用check(col1 IS NOT NULL)。这个check转not null也不会产生多余的扫描&lt;/li&gt;
&lt;li&gt;加字段有default易失会重写，可以用非易失不重写特性先加字段，不会重写。存量数据看情况update&lt;/li&gt;
&lt;li&gt;分区表attach时可以利用check约束减少停机时间，而添加check约束又可以用到validate constraint&lt;/li&gt;
&lt;li&gt;create table like+attach比partition of的锁低很多（但我还是喜欢parition of）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;变更后的注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&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%b9%b6%e5%8f%91%e5%88%9b%e5%bb%ba%e7%b4%a2%e5%bc%95" 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;p&gt;并行参数：&lt;code&gt;max_parallel_maintenance_workers&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;前提：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;worker是够的，需要检查&lt;code&gt;max_parallel_workers&lt;/code&gt;,&lt;code&gt;max_worker_processes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调整&lt;code&gt;maintenance_work_mem&lt;/code&gt; 上GB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对 B-tree or BRIN有效&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maintenance_work_mem&lt;/code&gt; limit to entire utility command。跟parallel query不同，parallel query的资源限制是 per worker process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从测试结果来看，并发建索引在8个并发以后收益不明显（这个结论在不同环境可能不保真）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分区表并发建索引：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;推荐分区子表手搓并发，即一次在多个分区上创建，而不是使用原生并发，这可以减少多进程交互代价。&lt;/p&gt;

&lt;h3 class="relative group"&gt;cached plan must not change resource
 &lt;div id="cached-plan-must-not-change-resource" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cached-plan-must-not-change-resource" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;业务前晚新增字段后，早上业务连接报错：&amp;ldquo;cached plan must not change result type in PostgreSQL&amp;rdquo;&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; a(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 style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; p1 (varchar) &lt;span style="color:#66d9ef"&gt;AS&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; a &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; b&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;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;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLUMN&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;TYPE&lt;/span&gt; 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;EXECUTE&lt;/span&gt; p1 (&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&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:#ae81ff"&gt;0&lt;/span&gt;A000: cached plan must &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; change &lt;span style="color:#66d9ef"&gt;result&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&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;: RevalidateCachedQuery, plancache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;718&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;code&gt;DEALLOCATE ALL&lt;/code&gt;主动丢弃prepared statement
或者，
&lt;code&gt;DISCARD ALL&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;DEALLOCATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALL&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--DISCARD ALL
&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; p1 (varchar) &lt;span style="color:#66d9ef"&gt;AS&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; a &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; b&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;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;EXECUTE&lt;/span&gt; p1 (&lt;span style="color:#e6db74"&gt;&amp;#39;abcd&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;生产环境的解决办法：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于是业务层报错，JDBC可识别&lt;code&gt;DEALLOCATE ALL&lt;/code&gt;,&lt;code&gt;DISCARD ALL&lt;/code&gt;，但是业务可能没有做过。当下生产可执行如下方案：&lt;/p&gt;
&lt;p&gt;解决办法（四选一）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由于hikari等连接池的轮询启用连接和轮询timeout机制，可kill idle会话，报错会逐渐减少&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同样是由于连接池的轮询启用连接和轮询timeout机制，可什么都不做，等连接池逐渐建立和启用新的连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果业务压力足够大，可考虑kill所有业务连接&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;em&gt;不&lt;/em&gt;推荐：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DDL后重启应用。有效，但不要建议“所有DDL后都应该重启应用”这样的方案&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autosave=conservative&lt;/code&gt;。有效，但会启用子事务。savepoint is set for each query, however the rollback is done only for rare cases like ‘cached statement cannot change return type’ or ‘statement XXX is not valid’ so JDBC driver rolls back and retries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;jdbc配置建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置jdbc事务回滚后自动重试：&lt;a href="https://developer.aliyun.com/article/741750" target="_blank" rel="noreferrer"&gt;https://developer.aliyun.com/article/741750&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;其他jdbc配置参考：&lt;a href="https://jdbc.postgresql.org/documentation/server-prepare/#corner-cases" target="_blank" rel="noreferrer"&gt;https://jdbc.postgresql.org/documentation/server-prepare/#corner-cases&lt;/a&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="#%e7%89%a9%e7%90%86%e5%a4%8d%e5%88%b6" 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%e8%af%a2%e5%86%b2%e7%aa%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;查询冲突是一个非常坑的特性，它直接影响了PG从库的查询是不那么好用的。查询冲突会导致从库延迟增加，而从库的拉数SQL本身要跑一段时间是符合逻辑的，这就导致PG管理者不得不在延迟管理和长SQL管理中做出平衡。而这个特性在其他关系型数据库中是不存在的。&lt;/p&gt;
&lt;p&gt;查询冲突要注意的隐蔽特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态表同样会产生查询冲突&lt;a href="https://www.modb.pro/db/1966415366276526080" target="_blank" rel="noreferrer"&gt;（见-从静态表查询冲突到其原理）&lt;/a&gt;，也就是说冲突是快照冲突，与查询的表本身的锁几乎没有关系，快照冲突是跨表的。&lt;/li&gt;
&lt;li&gt;长查影响短查。长查把从库延迟推到&lt;code&gt;max_standby_streaming_delay&lt;/code&gt;后，此时的短查也会被掐断。&lt;/li&gt;
&lt;li&gt;不停的短查也会引起查询冲突。例如上个短查还没有结束，下一个短查又开始了，这两个短查逻辑可能是类似的，此时startup进程还没有来得应用日志。这在跑批中比较常见。这两个短查都持有那个需要应用的xid，可以检查&lt;code&gt;pg_stat_activity.backend_xmin&lt;/code&gt;是否小于startup正在应用的xid&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查询从库推荐的实践：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过RTO SLO来调整&lt;code&gt;max_standby_streaming_delay&lt;/code&gt;是一个不错的选择。当吵架到没有结果时，使用SLO来进行IT管理会救命。&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;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%80%bb%e8%be%91%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;逻辑复制的坑可以说非常多了。24年有很多非常坑的案例，25年也遇到一些案例，但不算特别坑，而且主要是一些低版本pg上出现的，总体来看高版本的pg逻辑复制倾向稳定。&lt;/p&gt;

&lt;h3 class="relative group"&gt;低版本PG+DDL/DCL语句解析较慢
 &lt;div id="低版本pgddldcl语句解析较慢" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8e%e7%89%88%e6%9c%acpgddldcl%e8%af%ad%e5%8f%a5%e8%a7%a3%e6%9e%90%e8%be%83%e6%85%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1922232196358746112" target="_blank" rel="noreferrer"&gt;案例-授权和walsender跑不动&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PG13及之前的版本，对某些DDL、DCL语句解析较慢，可能会影响walsender延迟。这些DDL、DCL包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;批量授权（含grant all tables）+ 安装了pathman extension（无论是否使用）&lt;/li&gt;
&lt;li&gt;批量DDL/TRUNCATE/DCL/DROP PUBLICATION&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;低版本PG+多链路重复解析+flink
 &lt;div id="低版本pg多链路重复解析flink" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8e%e7%89%88%e6%9c%acpg%e5%a4%9a%e9%93%be%e8%b7%af%e9%87%8d%e5%a4%8d%e8%a7%a3%e6%9e%90flink" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;flink只能一个表一条链路，加上pg的walsender是重复解析的，一个pg库上几十条flink链路的walsender都是常见情况，而且改造困难。&lt;/p&gt;
&lt;p&gt;而在pg11及以前，在walsender主循环中有&lt;code&gt;PostmasterIsAlive()&lt;/code&gt;函数，导致主循环性能较差。从pg12开始&lt;code&gt;WalSndLoop&lt;/code&gt;函数没有在主循环中频繁轮询&lt;code&gt;PostmasterIsAlive()&lt;/code&gt;，而是将状态检查放到&lt;code&gt;WalSndWait&lt;/code&gt;中，通过事件机制被动等待通知。这极大的缓解了CPU的争用。&lt;/p&gt;
&lt;p&gt;如果库中有多个flink链路，而且pg版本较低，建议升级版本，可以缓解一定的walsender资源争用问题。这些可以缓解的资源问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可能会解决walsender启动时资源争用导致数据库长时间起不来的问题&lt;/li&gt;
&lt;li&gt;可能会解决上游大量数据变动（含DDL重写）导致runtime walsender解析日志的cpu打满问题&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="#%e4%bd%8e%e7%89%88%e6%9c%acpg%e6%97%a0%e6%b3%95%e8%87%aa%e5%8a%a8%e5%90%8c%e6%ad%a5%e6%96%b0%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PG声明式分区在低版本需要注意&lt;em&gt;仅&lt;/em&gt;能通过子表发布。&lt;a href="https://www.postgresql.org/docs/release/13.0/" target="_blank" rel="noreferrer"&gt;pg版本&amp;gt;=13才支持按照父表配置发布&lt;/a&gt;，低于这个版本只能按分区子表的名称配置同步：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Allow partitioned tables to be logically replicated via &lt;a href="https://www.postgresql.org/docs/13/sql-createpublication.html" target="_blank" rel="noreferrer"&gt;publications&lt;/a&gt; (Amit Langote) &lt;a href="https://postgr.es/c/17b9e7f9f" target="_blank" rel="noreferrer"&gt;§&lt;/a&gt; &lt;a href="https://postgr.es/c/83fd4532a" target="_blank" rel="noreferrer"&gt;§&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Previously, partitions had to be replicated individually. Now a partitioned table can be published explicitly, causing all its partitions to be published automatically. Addition/removal of a partition causes it to be likewise added to or removed from the publication. The &lt;a href="https://www.postgresql.org/docs/13/sql-createpublication.html" target="_blank" rel="noreferrer"&gt;&lt;code&gt;CREATE PUBLICATION&lt;/code&gt;&lt;/a&gt; option &lt;code&gt;publish_via_partition_root&lt;/code&gt; controls whether changes to partitions are published as their own changes or their parent&amp;rsquo;s.&lt;/p&gt;
&lt;/blockquote&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="#%e8%bf%81%e7%a7%bb%e5%92%8c%e5%8d%87%e7%ba%a7" 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="#%e8%bf%81%e7%a7%bb%e4%bf%a1%e5%88%9b%e5%92%8cglibc%e5%8d%87%e7%ba%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;无论是信创迁移还是LINUX OS版本升级，都可能涉及glibc的升级，而glibc升级可能会非常坑。pg的排序在17以前都是完全依赖操作系统的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg没有办法检测glibc升级带来的兼容性问题&lt;/strong&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;排序规则分了很多种，而很多环境用的是语义排序（例如en_US.utf8），语义排序也是最吃版本的。排序规则变化最常见的是引起查询索引时数据库奔溃，也还有其他不常见问题比如重复主键、分区表数据存入错误分区、merge join结果返回不一致等等。&lt;/p&gt;
&lt;p&gt;好在pg17提供了非常安全的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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initdb --locale-provider&lt;span style="color:#f92672"&gt;=&lt;/span&gt;builtin --bultin-locale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;C.UTF-8 dbname1&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;builtin虽然是个好东西但是来得太迟了。大量已投入使用的数据库实例，想转builtin的字符集可不是一件容易的事。而且，信创迁移或者OS升级可能不会将数据库升级作为强制动作。&lt;/p&gt;
&lt;p&gt;信创迁移时，信创主机的glibc版本一般都比老的英特尔服务器glibc版本高，很可能跨了2.28这个版本。加上任务急、kpi推动、人力不足和大库，物理迁移是在所难免。所以信创物理迁移得关注glibc版本和collation导致的许多异常。&lt;/p&gt;
&lt;p&gt;物理迁移后可以做什么？&lt;/p&gt;
&lt;p&gt;一、官方必修方案&lt;/p&gt;
&lt;p&gt;1.check索引，重建明显有问题的索引&lt;/p&gt;
&lt;p&gt;2.REFRESH DATABASE COLLATION VERSION&lt;/p&gt;
&lt;p&gt;3.检查依赖对象&lt;/p&gt;
&lt;p&gt;4.REFRESH COLLATION VERSION&lt;/p&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;p&gt;参考&lt;a href="https://docs.paic.com.cn/#/post/122695260" target="_blank" rel="noreferrer"&gt;collation&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="#%e4%b8%9d%e6%bb%91%e5%a4%a7%e7%89%88%e6%9c%ac%e5%8d%87%e7%ba%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://gitlab.com/postgres-ai/postgresql-consulting/postgres-howtos/-/blob/main/0077_zero_downtime_major_upgrade.md?ref_type=heads" target="_blank" rel="noreferrer"&gt;https://gitlab.com/postgres-ai/postgresql-consulting/postgres-howtos/-/blob/main/0077_zero_downtime_major_upgrade.md?ref_type=heads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.eu/events/pgconfeu2023/sessions/session/4791/slides/439/2023.pgconf.eu%20Zero%20Downtime%20PostgreSQL%20Upgrades.pdf" target="_blank" rel="noreferrer"&gt;https://www.postgresql.eu/events/pgconfeu2023/sessions/session/4791/slides/439/2023.pgconf.eu%20Zero%20Downtime%20PostgreSQL%20Upgrades.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一般的大版本升级方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg_upgrade原地升级。不推荐，可能原地爆炸。&lt;/li&gt;
&lt;li&gt;pgdump：适合小库，窗口期较长的库&lt;/li&gt;
&lt;li&gt;逻辑同步+switchover（发布订阅/pg_logical/dts等）：适合小库，窗口期较短的库&lt;/li&gt;
&lt;li&gt;物理正向同步+逻辑反向同步：适合大库，窗口期不太长的库&lt;/li&gt;
&lt;li&gt;物理复制全量+逻辑同步增量+switchover：适合大库，窗口期极短的库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用逻辑同步同步全量数据可能是非常慢的，而用新从库原地升级本身带有不确定性，有一定的升级时间，而且也要解决反向逻辑同步的问题。“丝滑大版本升级”其实就是“物理复制全量+逻辑同步增量+switchover”。&lt;/p&gt;
&lt;p&gt;丝滑大版本升级的主要技术：主库创建slot会返回LSN，新从库&lt;code&gt;recovery_target_lsn&lt;/code&gt; 恢复到这个LSN，然后开启逻辑同步。&lt;/p&gt;
&lt;p&gt;方案的大致流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;预检查。多db（多db要考虑应用一个slot lsn）、插件、pathman、trigger、外键、unlogged表、crontab等等&lt;/li&gt;
&lt;li&gt;物理同步。新老版本软件、对比和备份conf文件、pg_basebackup搭建低版本新库&lt;/li&gt;
&lt;li&gt;逻辑同步准备一。主键和复制标识、创建发布；禁止业务发布DDL/DCL&lt;/li&gt;
&lt;li&gt;新库恢复到target LSN。停新库；老库创建slot并记录LSN；新库以target LSN启动&lt;/li&gt;
&lt;li&gt;新库大版本升级。升级、处理各种问题、环境变量切换&lt;/li&gt;
&lt;li&gt;逻辑同步准备二。禁用trigger、外键、任务、插件等&lt;/li&gt;
&lt;li&gt;逻辑同步。创建指定slot的copy_data=false订阅&lt;/li&gt;
&lt;li&gt;逻辑同步后。索引损坏检查、检查日志报错并修复、重建同城远程&lt;/li&gt;
&lt;li&gt;switchover。停业务；提升序列、启用外键、trigger、任务等&lt;/li&gt;
&lt;li&gt;switchover。搭建反向链路（老库订阅）&lt;/li&gt;
&lt;li&gt;switchover。业务切换&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;丝滑大版本升级的方案对于业务很丝滑，对于DBA很复杂。这个方案包含了逻辑迁移和物理迁移的所有缺点，做起来是比较痛苦的，以上步骤已经简化过了。该方案消耗DBA人力，对于非常重要的库可以考虑这个方案。&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%e7%ae%a1%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Postgres分区表非常灵活，没有自增interval分区功能，而且版本多变，导致分区表运维管理问题几乎是年年发生。我相信有不少PG DBA对于新分区的各种问题还提心吊胆的。&lt;/p&gt;
&lt;p&gt;我自己观察下来分区表的管理和使用主要有如下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;未使用声明式分区表&lt;/strong&gt;。老版本仍然使用pathman分区或继承表分区，或者即便升级后仍然使用pathman分区或继承表分区。PG10开始支持声明式分区，由于早期版本有功能不足，建议至少PG12以后就&lt;em&gt;仅&lt;/em&gt;使用声明式分区表，以减少环境的复杂性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发自建子表索引/主键&lt;/strong&gt;。不通过父表默认继承而是通过SQL直接在子表建索引/主键，会导致下一次开发写SQL时可能就忘记了。这不仅会导致父子不一致，也会导致子子不一致，最终导致分区表结构面目全非。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;新分区无管理策略&lt;/strong&gt;。忘记建新分区或者用default分区。一般开发会建个几年的分区，下一次可能开发都换了一批了，没人会去管这个新分区建设。这会定时炸弹随时爆炸，或者数据写入default分区失去分区意义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺乏DBA的管理&lt;/strong&gt;。是的，DBA！PG的分区表知识实在是多（参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;），怎么基于自己的环境做管理策略和落地，需要专业DBA的主动推动。这可能是最重要的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自己思考的分区表管理目标（copy的这个&lt;a href="https://www.modb.pro/db/2007743085057499136" target="_blank" rel="noreferrer"&gt;案例-20260101分区数据更新失败&lt;/a&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以主表结构为标准结构，即主表面向开发，它上面应该有主键、索引、复制标识（pg版本不支持除外）&lt;/li&gt;
&lt;li&gt;主表与子表保持一致，使用partition of创建新分区（是的，我不推荐attach）&lt;/li&gt;
&lt;li&gt;子表与子表保持一致&lt;/li&gt;
&lt;li&gt;提前创建新分区，分区数据量不宜过多&lt;/li&gt;
&lt;li&gt;default分区不建议创建，如果创建必须监控其写入情况&lt;/li&gt;
&lt;li&gt;频繁访问的表的SQL必须包含分区键，使用分区裁剪，不然改造为普通表&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%af%e8%a7%82%e6%b5%8b%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从&lt;a href="https://www.postgresql.org/docs/18/monitoring-stats.html" target="_blank" rel="noreferrer"&gt;官方文档&lt;/a&gt;中基本都能看到数据库、表、索引、SQL、刷脏等等指标释义，还是比较清楚的。&lt;/p&gt;
&lt;p&gt;其中有几个指标可能要特别注意一下，不仅解释的不是很清楚，而且常用且有理解成本。&lt;/p&gt;

&lt;h3 class="relative group"&gt;buffers_alloc、blks_read
 &lt;div id="buffers_allocblks_read" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#buffers_allocblks_read" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pg_stat_bgwriter.buffers_alloc&lt;/code&gt;： Number of buffers allocated，共享内存置换量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pg_stat_database.blks_read&lt;/code&gt; ：os cache读&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（&lt;code&gt;buffers_alloc&lt;/code&gt;在不同PG版本可能在不同视图中，但含义不变）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg_stat_bgwriter.buffers_alloc&lt;/code&gt;是共享内存的buffer分配量，源码中叫buffer allocation。可以代表共享内存的置换量，新起的库一般这个值比较高。观察共享内存繁忙程度时，buffer allocate可能要比命中率好，命中率高可能就是小表频繁访问拉高了，allocate是产生了实质的置换的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;buffers_alloc&lt;/code&gt;是从cache读数后加载到新的共享内存buffer，其实也能一定程度代表os cache read吧？但是实际观察下来，&lt;code&gt;buffers_alloc&lt;/code&gt;与&lt;code&gt;blks_read&lt;/code&gt;含义如此相似但数值可能差异较大。为什么？没搞懂，待研究。&lt;/p&gt;
&lt;p&gt;源码：&lt;code&gt;numBufferAllocs&lt;/code&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;tup_fetched、tup_returned
 &lt;div id="tup_fetchedtup_returned" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tup_fetchedtup_returned" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这俩是&lt;code&gt;pg_stat_database&lt;/code&gt; 中的指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tup_fetched&lt;/code&gt; ：索引扫描最终获取的行数，去掉了过滤条件、死亡元组、不可见行后的行。偏向于结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tup_returned&lt;/code&gt; ：索引扫描回表的行数，不管是否满足过滤条件、死亡元组、不可见行后的行。偏向于处理过程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，&lt;code&gt;tup_returned&lt;/code&gt; 一般比&lt;code&gt;tup_fetched&lt;/code&gt; 高不少。而异常高，也代表可能有优化空间，因为毕竟访问了这么多数据，实际上没有返回给客户端多少。&lt;/p&gt;

&lt;h3 class="relative group"&gt;idx_tup_fetch 、idx_tup_read
 &lt;div id="idx_tup_fetch-idx_tup_read" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#idx_tup_fetch-idx_tup_read" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这俩是&lt;code&gt;pg_stat_all_indexes&lt;/code&gt; 中的指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;idx_tup_read&lt;/code&gt; ：从索引计数的访问索引条目数，包含bitmap scan&lt;/li&gt;
&lt;li&gt;&lt;code&gt;idx_tup_fetch&lt;/code&gt; ：从表计数的索引扫描最终返回的行数，不包含bitmap scan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;疯了&lt;/p&gt;
&lt;p&gt;可以记住一个点：&lt;code&gt;xx_tup_fetch&lt;/code&gt;&lt;strong&gt;是指经过索引回表访问后返回的最终行数，偏向于结果。&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="#%e5%8f%82%e8%80%83%e5%86%85%e5%ae%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://gitlab.com/postgres-ai/postgresql-consulting/postgres-howtos" target="_blank" rel="noreferrer"&gt;postgres-ai howtos&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgresql.us/events/pgconfnyc2024/sessions/session/1862/slides/172/pgvector_best_practices_pgconfnyc2024.pdf" target="_blank" rel="noreferrer"&gt;Best practices for using pgvector&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/2007743085057499136" target="_blank" rel="noreferrer"&gt;案例-20260101分区数据更新失败&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1976119963471589376" target="_blank" rel="noreferrer"&gt;案例-从distinct不准确到DISTINCT的计算原理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1964312913808732160" target="_blank" rel="noreferrer"&gt;案例-添加索引性能下降和generic plan&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1966415366276526080" target="_blank" rel="noreferrer"&gt;从静态表查询冲突到其原理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.modb.pro/db/1948643346948304896" target="_blank" rel="noreferrer"&gt;控制文件上的参数和主从参数不一致问题&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://liuzhilong.blog.csdn.net/article/details/130783036" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net/article/details/130783036&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://techcommunity.microsoft.com/blog/adforpostgresql/improving-postgres-connection-scalability-snapshots/1806462" target="_blank" rel="noreferrer"&gt;https://techcommunity.microsoft.com/blog/adforpostgresql/improving-postgres-connection-scalability-snapshots/1806462&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/17/sql-prepare.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/17/sql-prepare.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/17/sql-deallocate.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/17/sql-deallocate.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/13.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/13.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jdbc.postgresql.org/documentation/use/" target="_blank" rel="noreferrer"&gt;https://jdbc.postgresql.org/documentation/use/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jdbc.postgresql.org/documentation/server-prepare/#server-prepared-statements" target="_blank" rel="noreferrer"&gt;https://jdbc.postgresql.org/documentation/server-prepare/#server-prepared-statements&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.eu/events/pgconfeu2023/sessions/session/4791/slides/439/2023.pgconf.eu%20Zero%20Downtime%20PostgreSQL%20Upgrades.pdf" target="_blank" rel="noreferrer"&gt;https://www.postgresql.eu/events/pgconfeu2023/sessions/session/4791/slides/439/2023.pgconf.eu%20Zero%20Downtime%20PostgreSQL%20Upgrades.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;感谢25年跟高大师的battle&lt;/p&gt;</content:encoded></item><item><title>案例-20260101分区数据更新失败</title><link>https://lastdba.com/2026/01/04/%E6%A1%88%E4%BE%8B-20260101%E5%88%86%E5%8C%BA%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E5%A4%B1%E8%B4%A5/</link><pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/01/04/%E6%A1%88%E4%BE%8B-20260101%E5%88%86%E5%8C%BA%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E5%A4%B1%E8%B4%A5/</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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;12月30日发现业务报错，数据无法更新：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;ERROR: &lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; cannot update table &lt;span style="color:#e6db74"&gt;&amp;#34;tablzl_202601&amp;#34;&lt;/span&gt; because it does not have a replica identity and publishes updates
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOCATION: CheckCmdReplicaIdentity, execReplication.c:&lt;span style="color:#ae81ff"&gt;575&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="#%e4%b8%b4%e6%97%b6%e6%81%a2%e5%a4%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为报错信息充足，没有复制标识，表是一个分区表，又是26年的分区，所以直接怀疑新分区没有主键（新表的复制标识是default，default只能用主键作为复制标识，没有主键就会无法更新）。&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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;12月30日发现业务报错，数据无法更新：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;ERROR: &lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; cannot update table &lt;span style="color:#e6db74"&gt;&amp;#34;tablzl_202601&amp;#34;&lt;/span&gt; because it does not have a replica identity and publishes updates
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOCATION: CheckCmdReplicaIdentity, execReplication.c:&lt;span style="color:#ae81ff"&gt;575&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="#%e4%b8%b4%e6%97%b6%e6%81%a2%e5%a4%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为报错信息充足，没有复制标识，表是一个分区表，又是26年的分区，所以直接怀疑新分区没有主键（新表的复制标识是default，default只能用主键作为复制标识，没有主键就会无法更新）。&lt;/p&gt;
&lt;p&gt;然后发现，父表没有任何主键和索引，25年以前的老子分区有主键和索引，26年以后的新子分区没有任何主键和索引，且所有子分区有发布。大概如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;p_parent &lt;span style="color:#75715e"&gt;--无主键无索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p_child_202511 &lt;span style="color:#75715e"&gt;--有主键有索引，有发布
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p_child_202512 &lt;span style="color:#75715e"&gt;--有主键有索引，有发布
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p_child_202601 &lt;span style="color:#75715e"&gt;--无主键无索引，有发布
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p_child_202602 &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添加子分区也会什么都没有，只有自己准备子分区的主键和索引，所以推测新分区创建的有问题，老分区新建时应该是处理过的。&lt;/p&gt;
&lt;p&gt;另外，通过父表发布分区表是&lt;a href="https://www.postgresql.org/docs/release/13.0/" target="_blank" rel="noreferrer"&gt;PG13才开始支持&lt;/a&gt;，以前不能通过父表发布，只能通过子表发布，该库版本是PG11。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Allow partitioned tables to be logically replicated via &lt;a href="https://www.postgresql.org/docs/13/sql-createpublication.html" target="_blank" rel="noreferrer"&gt;publications&lt;/a&gt; (Amit Langote) &lt;a href="https://postgr.es/c/17b9e7f9f" target="_blank" rel="noreferrer"&gt;§&lt;/a&gt; &lt;a href="https://postgr.es/c/83fd4532a" target="_blank" rel="noreferrer"&gt;§&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Previously, partitions had to be replicated individually. Now a partitioned table can be published explicitly, causing all its partitions to be published automatically. Addition/removal of a partition causes it to be likewise added to or removed from the publication. The &lt;a href="https://www.postgresql.org/docs/13/sql-createpublication.html" target="_blank" rel="noreferrer"&gt;&lt;code&gt;CREATE PUBLICATION&lt;/code&gt;&lt;/a&gt; option &lt;code&gt;publish_via_partition_root&lt;/code&gt; controls whether changes to partitions are published as their own changes or their parent&amp;rsquo;s.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;初步知道问题后，因为情况紧急，可以通过3个办法来临时解决：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;26年新分区添加主键&lt;/li&gt;
&lt;li&gt;26年新分区设置replica identity full&lt;/li&gt;
&lt;li&gt;26年新分区取消发布表&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="#%e6%a0%b9%e5%9b%a0%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;问题看似清晰，就是“没有复制标识+发布过+没有主键”导致不能更新，但是还有一些问题需要解答。&lt;/p&gt;

&lt;h3 class="relative group"&gt;疑问一：为什么update没有更新202601的数据（新分区根本没有数据），仍然报错
 &lt;div id="疑问一为什么update没有更新202601的数据新分区根本没有数据仍然报错" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%96%91%e9%97%ae%e4%b8%80%e4%b8%ba%e4%bb%80%e4%b9%88update%e6%b2%a1%e6%9c%89%e6%9b%b4%e6%96%b0202601%e7%9a%84%e6%95%b0%e6%8d%ae%e6%96%b0%e5%88%86%e5%8c%ba%e6%a0%b9%e6%9c%ac%e6%b2%a1%e6%9c%89%e6%95%b0%e6%8d%ae%e4%bb%8d%e7%84%b6%e6%8a%a5%e9%94%99" 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;&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; tablzl_202601
&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; idid &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;1&lt;/span&gt;,...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_updated &lt;span style="color:#f92672"&gt;=&lt;/span&gt; now()
&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; mykey &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;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;&lt;code&gt;tablzl_202601&lt;/code&gt;表的分区键是&lt;code&gt;created_date&lt;/code&gt;，SQL条件就没有分区键，所以去更新202601分区发现连个主键都没有所以就报错了。&lt;/p&gt;
&lt;p&gt;至于检查是否有行和检查复制标识谁先，从&lt;code&gt;ExecSimpleRelationUpdate&lt;/code&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-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; * Find the searchslot tuple and update it with data in the slot,
&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 indexes, and execute any constraints and per-row triggers.
&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; * Caller is responsible for opening the indexes.
&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;ExecSimpleRelationUpdate&lt;/span&gt;(EState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;estate, EPQState &lt;span style="color:#f92672"&gt;*&lt;/span&gt;epqstate,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 TupleTableSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;searchslot, TupleTableSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;CheckCmdReplicaIdentity&lt;/span&gt;(rel, CMD_UPDATE); &lt;span 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;/* BEFORE ROW UPDATE Triggers */&lt;/span&gt; &lt;span style="color:#75715e"&gt;//before ROW UPDATE trigger
&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; (resultRelInfo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;ri_TrigDesc &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;		resultRelInfo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;ri_TrigDesc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;trig_update_before_row)
&lt;/span&gt;&lt;/span&gt;&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 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ExecBRUpdateTriggers&lt;/span&gt;(estate, epqstate, resultRelInfo,
&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;searchslot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tts_tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_self,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									NULL, 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:#66d9ef"&gt;if&lt;/span&gt; (slot &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)		&lt;span style="color:#75715e"&gt;/* &amp;#34;do nothing&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			skip_tuple &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:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;skip_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;		List	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;recheckIndexes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NIL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 the constraints of the 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:#66d9ef"&gt;if&lt;/span&gt; (rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_att&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;constr)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ExecConstraints&lt;/span&gt;(resultRelInfo, slot, estate);
&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; (resultRelInfo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;ri_PartitionCheck)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ExecPartitionCheck&lt;/span&gt;(resultRelInfo, slot, estate, 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;/* Materialize slot into a tuple that we can scribble upon. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		tuple &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ExecMaterializeSlot&lt;/span&gt;(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;/* OK, update the tuple and index entries for it */&lt;/span&gt; &lt;span style="color:#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;simple_heap_update&lt;/span&gt;(rel, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;searchslot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tts_tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_self,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tts_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; (resultRelInfo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;ri_NumIndices &lt;span style="color:#f92672"&gt;&amp;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 style="color:#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:#a6e22e"&gt;HeapTupleIsHeapOnly&lt;/span&gt;(slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tts_tuple))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			recheckIndexes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ExecInsertIndexTuples&lt;/span&gt;(slot, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;(tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_self),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;												 estate, false, NULL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;												 NIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* AFTER ROW UPDATE Triggers */&lt;/span&gt; &lt;span style="color:#75715e"&gt;//after ROW UPDATE trigger
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ExecARUpdateTriggers&lt;/span&gt;(estate, resultRelInfo,
&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;searchslot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tts_tuple&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;t_self,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							 NULL, tuple, recheckIndexes, 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;list_free&lt;/span&gt;(recheckIndexes);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;ExecSimpleRelationUpdate&lt;/code&gt;大致过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查复制标识&lt;/li&gt;
&lt;li&gt;before ROW UPDATE trigger&lt;/li&gt;
&lt;li&gt;检查约束（包括非分区约束和分区约束）&lt;/li&gt;
&lt;li&gt;更新行&lt;/li&gt;
&lt;li&gt;插入索引条目&lt;/li&gt;
&lt;li&gt;after ROW UPDATE trigger&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以pg逻辑就是先检查复制标识，然后才是更新行等等操作。&lt;/p&gt;
&lt;p&gt;虽然SQL条件没有分区键，但是加上分区键就会裁剪吗？答案是可能不会。&lt;/p&gt;
&lt;p&gt;分区裁剪的版本提升：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg10刚支持声明式分区，没有enable_partition_pruning参数，可以通过constraint_exclusion在planning阶段裁剪。所以pg10没有query process pruning&lt;/li&gt;
&lt;li&gt;pg11支持query process pruning，&lt;a href="https://www.postgresql.org/docs/release/11.0/" target="_blank" rel="noreferrer"&gt;Allow partition elimination during query execution (David Rowley, Beena Emerson)&lt;/a&gt;。但只支持绑定变量裁剪，不支持非immutable函数裁剪（包括&lt;code&gt;now()&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/release/14.0/" target="_blank" rel="noreferrer"&gt;pg14&lt;/a&gt;支持最终裁剪，&lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=c5b7ba4e6" target="_blank" rel="noreferrer"&gt;This wins in UPDATEs on partitioned tables when only some of the partitions will actually receive updates&lt;/a&gt;。即支持非immutable函数裁剪&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为pg11不支持now()裁剪，如果业务SQL加now()条件不会触发裁剪，仍然会报错。但是如果业务通过绑定变量传入，是会触发裁剪的，也就不会报错。注意，这个报错指的是更新202512的数据不会在202601分区上报错，更新202601的数据该报错还是报错。&lt;/p&gt;

&lt;h3 class="relative group"&gt;疑问二：表是20251226创建的,为什么是10月30日发现有问题
 &lt;div id="疑问二表是20251226创建的为什么是10月30日发现有问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%96%91%e9%97%ae%e4%ba%8c%e8%a1%a8%e6%98%af20251226%e5%88%9b%e5%bb%ba%e7%9a%84%e4%b8%ba%e4%bb%80%e4%b9%88%e6%98%af10%e6%9c%8830%e6%97%a5%e5%8f%91%e7%8e%b0%e6%9c%89%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;虽然新分区建的比较早，但发布表的时间是12月29日晚20:47&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;cat postgresql&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;.csv.bak &lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep &lt;span style="color:#e6db74"&gt;&amp;#34;alter publication&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;12&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;20&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;730&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;userlzlreplication&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,xxx&lt;span style="color:#e6db74"&gt;&amp;#34;statement: alter publication publzl add table &amp;#34;&amp;#34;public&amp;#34;&amp;#34;.&amp;#34;&amp;#34;tablzl_202601&amp;#34;&amp;#34;, &amp;#34;&amp;#34;public&amp;#34;&amp;#34;.&amp;#34;&amp;#34;tablzl_202602&amp;#34;&amp;#34;,...,,,,,,,,,&amp;#34;&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;首次报错时间是12月29日晚22:26，也就是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; cat postgresql&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;.csv.bak &lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep &lt;span style="color:#e6db74"&gt;&amp;#34;REPLICA IDENTITY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;12&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;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;404&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;userlzlreplication&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;375121&lt;/span&gt;,xxx,&lt;span style="color:#e6db74"&gt;&amp;#34;cannot update table &amp;#34;&amp;#34;tablzl_202601&amp;#34;&amp;#34; because it does not have a replica identity and publishes updates&amp;#34;&lt;/span&gt;,,&lt;span style="color:#e6db74"&gt;&amp;#34;To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.&amp;#34;&lt;/span&gt;,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE tablzl&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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;原因概述：如果父表没有主键，新分区partition of创建时当然也不会有主键，老的子分区通过子分区主键实现，新的子分区没有去主动创建主键，导致202601主键缺失。链路同步需要依赖主键（default）作复制标识，没有复制标识会导致无法同步给下游，也会导致发布以后update/delete语句无法正常执行。在PG 11中，update SQL本身即使包含分区键条件，也&lt;em&gt;可能&lt;/em&gt;会去访问新分区。&lt;/p&gt;
&lt;p&gt;运气成分：因为各种原因，这个库提前发现了这个问题。在31号我们有1天的buffer来补救所有数据库实例，至少保证1号新分区数据update别报错，不然大概率2026年1月1日多个系统将原地爆炸。&lt;/p&gt;
&lt;p&gt;临时措施（三选一）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;26年新分区添加主键&lt;/li&gt;
&lt;li&gt;26年新分区设置replica identity full&lt;/li&gt;
&lt;li&gt;26年新分区取消发布表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于复制链路的优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应该提前发现没有主键的表，不然直接发布的话，可能会导致业务侧更新失败&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于分区管理的策略：&lt;/p&gt;
&lt;p&gt;PG的分区表非常灵活，而且一般开发弄不懂怎么去正确创建分区，再加上分区表在大概PG10-15之间有较多的重要新特性，加上PG分区表没有interval分区功能，分区表可能弄的乱七八糟，所以规范管理分区表显得尤为重要。分区表的特性和运维技巧见：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;针对管理手段就不说了，&lt;/p&gt;
&lt;p&gt;针对管理目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以主表结构为标准结构，即主表面向开发，它上面应该有主键、索引、复制标识（pg版本不支持除外）&lt;/li&gt;
&lt;li&gt;主表与子表保持一致，使用partition of创建新分区（是的，我不推荐attach）&lt;/li&gt;
&lt;li&gt;子表与子表保持一致&lt;/li&gt;
&lt;li&gt;提前创建新分区，分区数据量不宜过多&lt;/li&gt;
&lt;li&gt;default分区不建议创建，如果创建必须监控其写入情况&lt;/li&gt;
&lt;li&gt;频繁访问的表的SQL必须包含分区键，使用分区裁剪，不然改造为普通表&lt;/li&gt;
&lt;/ul&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://www.postgresql.org/docs/release/10.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/10.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/11.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/11.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/12.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/12.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/13.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/13.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/14.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/14.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;src/backend/executor/execReplication.c&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>论文精读：插件无政府状态</title><link>https://lastdba.com/2026/01/03/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BB%E6%8F%92%E4%BB%B6%E6%97%A0%E6%94%BF%E5%BA%9C%E7%8A%B6%E6%80%81/</link><pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/01/03/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BB%E6%8F%92%E4%BB%B6%E6%97%A0%E6%94%BF%E5%BA%9C%E7%8A%B6%E6%80%81/</guid><description>&lt;p&gt;论文：Anarchy in the Database: A Survey and Evaluation of Database Management System Extensibility&lt;/p&gt;
&lt;p&gt;github：https://github.com/cmu-db/ext-analyzer&lt;/p&gt;
&lt;p&gt;pgconf：The trouble with extensions (PGConf.dev 2025)&lt;/p&gt;</description><content:encoded>&lt;p&gt;论文：Anarchy in the Database: A Survey and Evaluation of Database Management System Extensibility&lt;/p&gt;
&lt;p&gt;github：https://github.com/cmu-db/ext-analyzer&lt;/p&gt;
&lt;p&gt;pgconf：The trouble with extensions (PGConf.dev 2025)&lt;/p&gt;

&lt;h2 class="relative group"&gt;why this paper
 &lt;div id="why-this-paper" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#why-this-paper" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这是一篇数据库插件综述（主要是Postgres），主要讲不同数据库插件的实现方式、存在的问题和最重要的兼容性。其中最重磅的结论是：对 400 多个 PostgreSQL 扩展的评估显示，其中 16.8% 的扩展与至少一个其他扩展存在兼容性问题，且可能导致系统故障。&lt;/p&gt;
&lt;p&gt;分析工具和结果见github；Marco Slot的ppt演讲见PGconf。&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%8f%92%e4%bb%b6%e7%b1%bb%e5%88%ab" 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%8f%92%e4%bb%b6%e5%88%86%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;插件分类章节特别冗长，其实一个图就能看明白了。&lt;/p&gt;
&lt;p&gt;6种数据库的插件：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c2025f80a5c9.png" alt="image-20251228140624785" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL（1986）：C 语言编写，从设计之初就定位为可扩展架构。因此，PostgreSQL 拥有最为丰富多样的可扩展生态网络。&lt;/li&gt;
&lt;li&gt;MySQL（1994）： C++ 语言编写，其最知名的特性是存储引擎插件架构。&lt;/li&gt;
&lt;li&gt;MariaDB（2009）：作为 MySQL 的分支版本，它同样基于 C++ 开发，支持的扩展数量比原版 MySQL 更多。&lt;/li&gt;
&lt;li&gt;SQLite（2000）：嵌入式数据库，C 语言编写，可适配各类硬件设备与操作系统环境。&lt;/li&gt;
&lt;li&gt;Redis（2009）：内存型键值库，C++ 语言编写，其可扩展性独具特色 —— 仅支持在 DBMS key-value存储层之上运行。&lt;/li&gt;
&lt;li&gt;DuckDB（2018）：嵌入式分析型数据库，C++ 编写，拥有快速兴起的可扩展生态系统。&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%81%b5%e6%b4%bb%e6%80%a7%e5%92%8c%e5%ae%89%e5%85%a8%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;插件的安全性和灵活性只能二选一，pg的插件是最灵活也是最不安全的，redis是最安全也最不灵活的：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a4b3110396a3.png" alt="image-20260103140026801" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;postgres的插件一般怎么实现的
 &lt;div id="postgres的插件一般怎么实现的" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%9a%84%e6%8f%92%e4%bb%b6%e4%b8%80%e8%88%ac%e6%80%8e%e4%b9%88%e5%ae%9e%e7%8e%b0%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg总体有两种方式实现扩展：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过handler function实现，如UDF,UDTs, external tables, storage engines, and index access methods.&lt;/li&gt;
&lt;li&gt;通过hooks钩子实现扩展。将钩子声明为全局变量中的函数指针，如果设置了钩子，它将调用这些指针而不是自己的代码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现方式可能是都包含的，并不排他。其他5个库的实现总体类似，但是&lt;strong&gt;他们都没有hooks这种形式的实现&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a0199291618a.png" alt="image-20251228170307440" /&gt;&lt;/p&gt;
&lt;p&gt;插件可能使用不同的方式来实现，比如funcion+types+index am，这就是可扩展性类型数量（number of extensibility types）。从figure 1可以看到有1-3中类型的扩展是最多的，而使用最多的实现方式就是function。&lt;/p&gt;
&lt;p&gt;从table3可以看出，有92.5%的插件都在使用UDF，毕竟是面向用户的特性，开发最为方便、门槛低。最少的是客户端认证，因为这种场景本身也不多。&lt;/p&gt;

&lt;h2 class="relative group"&gt;插件代码的copy率
 &lt;div id="插件代码的copy率" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e4%bb%b6%e4%bb%a3%e7%a0%81%e7%9a%84copy%e7%8e%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;文章还进行了一个有趣的调查研究，插件代码从build-in代码中的copy情况：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/69d841de287f.png" alt="image-20260103104107929" /&gt;&lt;/p&gt;
&lt;p&gt;441个插件中有16.6%&amp;ndash;73个插件含有至少1行从PG源码中copy的代码。详细分布如上图左。&lt;/p&gt;
&lt;p&gt;为什么有这么多插件是copy的代码呢？因为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg源码中有些是静态声明的函数，只能在本文件中调用，所以只能copy&lt;/li&gt;
&lt;li&gt;因为插件本身的需求，函数可能需要做出一点调整，所以只能copy出来调整&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而插件一般copy函数调整了多少呢？如上图右。&lt;/p&gt;
&lt;p&gt;可以看出，原封不动copy的其实是很少的。&lt;/p&gt;
&lt;p&gt;总之，插件代码从pg源码中copy，是因为某些原因而不得已的，整体copy率也不高。&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="#%e9%87%8d%e7%a3%85pg%e6%8f%92%e4%bb%b6%e7%9a%84%e5%85%bc%e5%ae%b9%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这是这篇文章最有趣的部分，总计对96个extension进行1对1的兼容性测试，测试发现有16.8%的两个插件是不兼容的！&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6d87c80af09b.png" alt="image-20260103111359805" /&gt;&lt;/p&gt;
&lt;p&gt;测试方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装。是的，安装就可能有问题了，并且作者进行了A-&amp;gt;B,B-&amp;gt;A两种顺序的安装和测试，所以可以看到图是不对称的&lt;/li&gt;
&lt;li&gt;运行扩展提供的单元测试&lt;/li&gt;
&lt;li&gt;pgbench。冒烟测试。pgbench当然很简单，不过结果很不错的话也可以说明一定问题了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在兼容性最差的插件top20里面，也能看到很多常见的插件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;常用的插件：pg_hint_plan,vector,pg_show_plans,pgsentinel,pg_cron,pg_stat_kcache&lt;/li&gt;
&lt;li&gt;很重的插件：citus,timescaledb&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些极其常见的插件和明星插件的兼容性可以这么差，这个结果足以惊掉下巴。&lt;/p&gt;
&lt;p&gt;细思极恐的是，这还只是简单的捉对测试，3-10个插件的运行才应该是生产常态，而且生产环境也比论文中的三种测试方式更加复杂多变。&lt;/p&gt;
&lt;p&gt;最后论文还提出插件兼容性较差的原因：插件使用越多的组件、扩展type、hooks，就越有可能跟其他扩展不兼容。&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%8c%91%e5%88%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;其实还是研究的postgres&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;文章标题是写DBMS的，但主要还是写pg的兼容性，mysql、redis等等的兼容性只是综述带过，完全没有实验数据。（虽然综述也很有意思，可以了解到mysql和redis的插件是怎么实现的）。&lt;/p&gt;
&lt;p&gt;另一个方面，这个文章有一种另类”总-分-总“的感觉，“ DBMS-postgres-DBMS”&amp;#x1f605;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;兼容性测试不足&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PG有400+插件，只测试了其中96个兼容性测试，也只有1-1的兼容性测试，不包含3个插件及以上的测试。兼容性测试不算特别全面。&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;p&gt;PG的插件确实很多很灵活，数量也很多，你都很难找到哪些是PG插件&lt;em&gt;不支持&lt;/em&gt;的功能。但是插件本身几乎是“无政府状态”，插件的开发和使用都有些问题。&lt;/p&gt;
&lt;p&gt;从兼容性结果来看，插件的兼容性是比较差的，甚至插件的安装顺序影响兼容性，多插件本身也依赖hook的执行顺序，比如2个插件都要求自己最后执行就比较尴尬了。“什么都有”不代表“什么都装”。&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%8f%92%e4%bb%b6%e7%9a%84%e5%ae%89%e5%85%a8%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PG的插件在安全层面管理几乎是没有的，无论是插件本身不安全还是用户使用插件提权。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果扩展包含有不安全的语言，能限制其行为的只有OS而不是DBMS&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果扩展可以访问用户空间，OS层就做不了管理了&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过查询（如UDF）实现的extension基本不会绕过ACL策略。虽然UDF更安全，但是也不是绝对安全，因为可以有含管理员权限的UDF。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单hook可能不会受到ACL的限制，因为在postgres中ACL只在planning和execution层执行。PG提供了&lt;code&gt;SECURITY LABEL&lt;/code&gt;来限制对象（包括插件）的访问控制&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="#%e8%bd%af%e4%bb%b6%e7%ae%a1%e7%90%86%e7%9a%84%e5%93%b2%e5%ad%a6%e6%80%9d%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;“如果扩展包含有不安全的语言，能限制其行为的只有OS而不是DBMS”&lt;/p&gt;
&lt;p&gt;这句话本身没有毛病，但是含有“你的目录会被删除”的暗示。为了反驳一下这句话，可以这样思考。&lt;/p&gt;
&lt;p&gt;如果你使用这款软件，那么就是信任这款软件，如同pg本身一样（但即使使用pg这款软件，也需要建立postgres这个os user，而不是直接使用root）。至于插件，可以把它当成pg软件的一部分。pg之所以被信任，能直接在生产环境安装，是因为业界有口皆碑。同样插件也是一样的，选择有口皆碑的插件，而不是胡乱使用。这本质上是postgres社区把关和插件提供方把关的区别。对于云服务商，很多插件都是不支持的，云服务商承担了插件把关的职能和背锅的责任。&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%88%e6%9c%ac%e6%94%b6%e6%95%9b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg的插件版本有这些特性：&lt;/p&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;/ul&gt;
&lt;p&gt;这就导致对插件版本没有管理的话，会出现多到难以管理的软件version。针对这个问题，限制不同PG版本安装指定的某一个插件版本，是一个不错的选择。至于处于某些需求的原因需要插件升级，通过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="#%e4%bd%bf%e7%94%a8%e6%8f%92%e4%bb%b6%e6%97%b6%e8%a6%81%e8%80%83%e8%99%91%e5%85%bc%e5%ae%b9%e6%80%a7%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;既然插件兼容性不怎么样，那么&lt;strong&gt;管理插件变得尤为重要&lt;/strong&gt;，我们不希望数据库返回奇怪的结果甚至跑着跑着就挂了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;插件管理策略：1.安装必要插件 2.再按需创建需要的插件 3.不要装没什么人用的插件&lt;/li&gt;
&lt;li&gt;搜索兼容性矩阵。虽然PG兼容性测试并不完美，但还是有价值的。因为论文不好直接搜兼容性矩阵，但可以“ctrl+f”搜索&lt;a href="https://github.com/cmu-db/ext-analyzer/blob/main/plot_scripts/csvs/compatibility_results.csv" target="_blank" rel="noreferrer"&gt;ext-analyzer的兼容性表格&lt;/a&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="#%e8%b6%a3%e9%97%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在1976年的INGRES论文中，已通过扩展实现了UDF；即使是POSTGRES，也在1986年的初始版本中转移了这个功能实现。而ORACLE 的UDF实现是ORACLE 7，release时间是&lt;a href="https://www.orafaq.com/wiki/Oracle_7" target="_blank" rel="noreferrer"&gt;1992年&lt;/a&gt;，比PG晚不少。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/da3915cf7a37.png" alt="image-20251228104850349" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2830dc6d8871.png" alt="image-20251228104840046" /&gt;&lt;/p&gt;
&lt;p&gt;而SQL标准是1996年才包含了UDF，离INGRES的UDF过去了整20年。stone braker确实是不太注重标准的推动。&lt;/p&gt;</content:encoded></item><item><title>案例-行锁与LWlock-lockmanger</title><link>https://lastdba.com/2025/12/21/%E6%A1%88%E4%BE%8B-%E8%A1%8C%E9%94%81%E4%B8%8Elwlock-lockmanger/</link><pubDate>Sun, 21 Dec 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/12/21/%E6%A1%88%E4%BE%8B-%E8%A1%8C%E9%94%81%E4%B8%8Elwlock-lockmanger/</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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;数据库有大量行锁和少部分LWlock lockmanger，cpu打满，活动会话飙升。锁对应的block pid在变化，未见明显长事务阻塞。
(脑补cpu和活动会话高）&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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;数据库有大量行锁和少部分LWlock lockmanger，cpu打满，活动会话飙升。锁对应的block pid在变化，未见明显长事务阻塞。
(脑补cpu和活动会话高）&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:#66d9ef"&gt;UPDATE&lt;/span&gt; lzl_record &lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; rc_lzl1&lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc_lzl1 &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;1&lt;/span&gt;, pc_lzl2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pc_lzl2 &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;2&lt;/span&gt;, rc_lzl3 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc_lzl3 &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;3&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; lzl_id &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;4&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%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#sql%e6%9c%aa%e8%a7%81%e5%b9%b6%e5%8f%91%e4%b8%8a%e6%b6%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;从hit和cpu的关联性看，可以从sql的hit分析。其中那个UPDATE sql占比80%左右，该sql的执行次数没有变化，但blks hit明显异常。&lt;/p&gt;
&lt;p&gt;同时分析元数据访问，快照内均元数据表没有访问特别高的。&lt;/p&gt;
&lt;p&gt;从现象分析看不出来SQL并发上涨，也看不出来元数据异常。SQL hit上涨暂时看不出来为什么。&lt;/p&gt;

&lt;h3 class="relative group"&gt;LWlock lockmanager分析
 &lt;div id="lwlock-lockmanager分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lwlock-lockmanager%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为SQL本身简单，lzl_record表的lzl_id字段是唯一字段，也就是通过唯一键进行更新。&lt;/p&gt;
&lt;p&gt;现场的等待事件除了大量的显示锁以外，还有LWlock lockmanager。&lt;/p&gt;
&lt;p&gt;但表是普通表不是分区表，且表上只有4、5个索引。&lt;/p&gt;
&lt;p&gt;LWlock lockmanger跟没有用到fast path有关系，而简单的查询、DML可以用到fastpath&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Weak relation locks. SELECT, INSERT, UPDATE, and DELETE must acquire a
lock on every relation they operate on, as well as various system catalogs
that can be used internally. Many DML operations can proceed in parallel
against the same table at the same time; only DDL operations such as
CLUSTER, ALTER TABLE, or DROP &amp;ndash; or explicit user action such as LOCK TABLE
&amp;ndash; will create lock conflicts with the &amp;ldquo;weak&amp;rdquo; locks (AccessShareLock,
RowShareLock, RowExclusiveLock) acquired by DML operations.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;所以，一个不超过访问16个relation（含索引）的SELECT/DML是可以用到fastpath的，就不应该有很多LWlock lockmanager。&lt;/p&gt;
&lt;p&gt;但是，DML肯定不能简单的用fastpath，fastpath是完全本地化处理锁，DML肯定需要校验其他会话是否持有行，需要访问共享内存。再加上SQL通过唯一字段更新还能有行锁，说明肯定更新的是同一行。&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="#%e5%8e%8b%e6%b5%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;压测同一行更新产生LWLock LockManager
 &lt;div id="压测同一行更新产生lwlock-lockmanager" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8b%e6%b5%8b%e5%90%8c%e4%b8%80%e8%a1%8c%e6%9b%b4%e6%96%b0%e4%ba%a7%e7%94%9flwlock-lockmanager" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;出于行锁肯定不能仅fastpath的考虑，以及LWLock LockManager会降低数据库性能的经验，压测不同场景性能情况。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;#prompt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;给我一个pgbench压测脚本
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;脚本略，套餐20c96g&lt;/p&gt;
&lt;p&gt;pgbench命令如下&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;pgbench -h localhost -p $PGPORT -d lzldb -U dbmgr -f update_same_unique_key.sql -c &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; -j &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; -T &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; -r -S
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pgbench -h localhost -p $PGPORT -d lzldb -U dbmgr -f update_random_unique_key.sql -c &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; -j &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; -T &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; -r -S&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;--更新同一行，常见2次等待
&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; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cnt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LockManager &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;105&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &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; &lt;span style="color:#ae81ff"&gt;61&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tuple &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; &lt;span style="color:#ae81ff"&gt;25&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; active &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;8&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALSync &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cnt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; transactionid &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; &lt;span style="color:#ae81ff"&gt;180&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LockManager &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tuple &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; &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALSync &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--更新不同行，常见2次等待
&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; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cnt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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; active &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;106&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; idle &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34&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; idle &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; BufferMapping &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&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; idle &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;transaction&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:#ae81ff"&gt;4&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; idle &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &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; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cnt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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; active &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;117&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; idle &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; idle &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&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; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; XactGroupUpdate &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IPC &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WALSync &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; XactSLRU &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; BufferContent &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &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; dbmgr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Client &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;从等待事件上可以看出差异，更新同一行会出现LWLock LockManager甚至占比较高的情况，不同行基本都是等cpu。场景1与生产情况类似。&lt;/p&gt;

&lt;h2 class="relative group"&gt;行锁与fastpath浅析
 &lt;div id="行锁与fastpath浅析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e4%b8%8efastpath%e6%b5%85%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;lmgr readme对fastpath的解释：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Fast Path Locking
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Fast path locking is a special purpose mechanism designed to reduce the
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;overhead of taking and releasing certain types of locks which are taken
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;and released very frequently but rarely conflict. Currently, this includes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;two categories of locks:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(1) Weak relation locks. SELECT, INSERT, UPDATE, and DELETE must acquire a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lock on every relation they operate on, as well as various system catalogs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;that can be used internally. Many DML operations can proceed in parallel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;against the same table at the same time; only DDL operations such as
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLUSTER, ALTER TABLE, or DROP -- or explicit user action such as LOCK TABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-- will create lock conflicts with the &amp;#34;weak&amp;#34; locks (AccessShareLock,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RowShareLock, RowExclusiveLock) acquired by DML operations.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;能使用fastpath的锁的条件&lt;code&gt;lmgr/lock.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;/*
&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 fast-path lock mechanism is concerned only with relation locks on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * unshared relations by backends bound to a database. The fast-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; * mechanism exists mostly to accelerate acquisition and release of locks
&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 rarely conflict. Because ShareUpdateExclusiveLock 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; * self-conflicting, it can&amp;#39;t use the fast-path mechanism; but it also does
&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 conflict with any of the locks that do, so we can ignore it completely.
&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 EligibleForRelationFastPath(locktag, 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;	((locktag)-&amp;gt;locktag_lockmethodid == DEFAULT_LOCKMETHOD &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:#75715e"&gt;	(locktag)-&amp;gt;locktag_type == LOCKTAG_RELATION &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:#75715e"&gt;	(locktag)-&amp;gt;locktag_field1 == MyDatabaseId &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:#75715e"&gt;	MyDatabaseId != InvalidOid &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:#75715e"&gt;	(mode) &amp;lt; ShareUpdateExclusiveLock)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;SELECT/DML是可以使用fastpath的，但是仅限于locktype=relation。&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:#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;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;update&lt;/span&gt; lzl1 &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;zzz&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;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;--窗口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;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;update&lt;/span&gt; lzl1 &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;zzz&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;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;--waiting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span 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;--窗口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;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&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:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_backend_pid()) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; pid,locktype;
&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; page &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tuple &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; classid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; objid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; objsubid &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 style="color:#f92672"&gt;|&lt;/span&gt; fastpath 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 style="color:#f92672"&gt;|&lt;/span&gt; t
&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:#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:#ae81ff"&gt;170706189&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 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:#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:#ae81ff"&gt;170706190&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 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:#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:#ae81ff"&gt;170706187&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 style="color:#f92672"&gt;|&lt;/span&gt; f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tuple &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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:#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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 style="color:#f92672"&gt;|&lt;/span&gt; f
&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:#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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;562&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 style="color:#f92672"&gt;|&lt;/span&gt; t
&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:#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:#ae81ff"&gt;170706187&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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;562&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 style="color:#f92672"&gt;|&lt;/span&gt; f
&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:#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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;562&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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;562&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 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的行锁实现比较复杂，不仅有tuple锁，还需要transactionid和relation锁。其中只有locktype=relation、virtualxid能用到fastpath，其他都用不到。&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:#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;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;update&lt;/span&gt; lzl1 &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;zzz&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;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;--窗口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;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;update&lt;/span&gt; lzl1 &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;zzz&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 style="color:#75715e"&gt;--waiting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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_locks &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; pid&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_backend_pid()) &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; pid,locktype;
&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; page &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tuple &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; classid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; objid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; objsubid &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 style="color:#f92672"&gt;|&lt;/span&gt; fastpath 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4792&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4792&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 style="color:#f92672"&gt;|&lt;/span&gt; t
&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:#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:#ae81ff"&gt;170706214&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4792&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 style="color:#f92672"&gt;|&lt;/span&gt; f
&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:#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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4792&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:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4792&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;220559&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 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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;563&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 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;4267681&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5290151&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 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;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;563&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 style="color:#f92672"&gt;|&lt;/span&gt; t
&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:#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:#ae81ff"&gt;170706212&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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;563&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 style="color:#f92672"&gt;|&lt;/span&gt; f
&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:#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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;563&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:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;563&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;253641&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 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;fastpath=f的也就少了2、3个。2个会话持有的transactionid锁是肯定用不到fastpath了。&lt;/p&gt;
&lt;p&gt;总结使用fastpath锁机制的场景（且）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;锁等级&amp;lt;=3，即SELECT/DML语句&lt;/li&gt;
&lt;li&gt;locktype=relation。pg的行锁还至少需要transactionid和tuple锁，所以这俩用不到fastpath&lt;/li&gt;
&lt;li&gt;relation数少于16个（一般分区表全分区访问就超了）&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;p&gt;1.行锁是因是果，是行锁的问题还是数据库性能下降SQL跑的慢了出现行锁？&lt;/p&gt;
&lt;p&gt;行锁是因。sql执行次数没有变化，但是sql的传参从离散变成集中，即更新同一行的情况明显增加。从压测数据来看更新同一行会出现行锁和LWLock LockManager的等待。&lt;/p&gt;
&lt;p&gt;2.sql执行次数没有上涨，SQL性能是否下降？&lt;/p&gt;
&lt;p&gt;SQL性能其实是下降了，但是索引肯定没有走错，只是因为反复更新了同一行。&lt;/p&gt;
&lt;p&gt;解决方案：&lt;/p&gt;
&lt;p&gt;从业务层了解SQL是某接口开关调用后讲调用次数更新到表里。如果是同一接口反复调用，是可能出现反复更新同一行的情况的。所以，减少同一接口反复调用或者更大批次的更新数据库，预计可以减缓这个问题。&lt;/p&gt;</content:encoded></item><item><title>论文精读：DBAIOps</title><link>https://lastdba.com/2025/12/21/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BBdbaiops/</link><pubDate>Sun, 21 Dec 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/12/21/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BBdbaiops/</guid><description>&lt;p&gt;论文：&lt;a href="https://www.arxiv.org/pdf/2508.01136" target="_blank" rel="noreferrer"&gt;DBAIOps: A Reasoning LLM-Enhanced Database Operation and Maintenance System using Knowledge Graphs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;repo：https://github.com/weAIDB/DBAIOps/&lt;/p&gt;

&lt;h2 class="relative group"&gt;什么是DBAIOps
 &lt;div id="什么是dbaiops" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%afdbaiops" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;1.why DBAIOps：&lt;/p&gt;</description><content:encoded>&lt;p&gt;论文：&lt;a href="https://www.arxiv.org/pdf/2508.01136" target="_blank" rel="noreferrer"&gt;DBAIOps: A Reasoning LLM-Enhanced Database Operation and Maintenance System using Knowledge Graphs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;repo：https://github.com/weAIDB/DBAIOps/&lt;/p&gt;

&lt;h2 class="relative group"&gt;什么是DBAIOps
 &lt;div id="什么是dbaiops" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%afdbaiops" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;1.why DBAIOps：&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;li&gt;文档+RAG模型不准确（没有DBA经验集成或有限制的局限性）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之，人力运维和现有方案都一般般，所以推出了DBAIOps——&lt;strong&gt;结合大模型推理和知识图谱的运维系统，实现类DBA的诊断能力&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;2.数据库故障分析方案对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预设规则方案：传统方案，比较死板&lt;/li&gt;
&lt;li&gt;机器学习方案：本质上是基于规则的，有许多类似的限制；依赖训练数据，会造成较低的生成能力，一般适合特点问题常见的诊断。&lt;/li&gt;
&lt;li&gt;基于LLM方案：使用一般文档和LLM（例如基于决策树），容易给出一般结果&lt;/li&gt;
&lt;li&gt;LLM+RAG方案：搜索基于分片的top-k临近知识，结果不准确&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.对比了以上方案后，可以看出&lt;strong&gt;结合了图知识、DBA经验、LLM的DBAIOps的优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结合DBA经验&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;h2 class="relative group"&gt;overview
 &lt;div id="overview" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#overview" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0901d29f4881.png" alt="image-20251214092938211" /&gt;&lt;/p&gt;
&lt;p&gt;左侧是架构，右侧是示例。&lt;/p&gt;
&lt;p&gt;offline做的是DBA经验嵌入neo4j，嵌入后的图模型叫ExperienceGraph，图的边代表异常现象或者metric的关系。嵌入后的异常模型称为AnomalyModel。&lt;/p&gt;
&lt;p&gt;online做的是异常分析、检索、生成报告。其中AnomalyProcessor提取标准故障信息和AnomalyModel信息，然后通过ExperienceRetriever检索图；最后RootCauseAnlyser调用LLM生成分析报告。&lt;/p&gt;
&lt;p&gt;从右侧的示例可以看到，通过图相关性找到LOG FILE SYNC关联的LOG WRITE性能、IO性能；通过REDO ALLOCATION可以找到表结构变更和DDL。&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%90%e7%bb%b4%e7%bb%8f%e9%aa%8c%e7%9a%84%e5%9b%be%e6%a8%a1%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;不同于基于规则或者基于文档chunk的RAG，ExperienceGraph是编码了运维经验异构信息的图模型。图包含三个元素：（顶点、带方向的边，边上的关系）。&lt;/p&gt;
&lt;p&gt;根据运维经验的特性，DBAIOps对其中顶点进行了分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;trigger vertex：用于检测数据库异常，是异常分析的入口。例如LOG FILE SYNC就是入口顶点&lt;/li&gt;
&lt;li&gt;metric vertex：数据库运行时的metric。如果是离线知识，指的应该是运维案例里的metric（如果有的话）&lt;/li&gt;
&lt;li&gt;experience vertex：编码了领域特定的运维经验，涵盖异常的含义及处置方法。比如LOG FILE SYNC超过60ms代表提交过于频繁或者其他参数需要调整。&lt;/li&gt;
&lt;li&gt;tool vertex：收集和分析异常指标的可执行脚本&lt;/li&gt;
&lt;li&gt;tag vertex：图顶点的语义类别。比如并发事务Concurrent Transactions涉及多种顶点，tag vertex可以加强跨案例的关联性&lt;/li&gt;
&lt;li&gt;auxiliary vertex：解释指标的含义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对边的分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;containment edge：Trigger Vertex-Experience Vertex&lt;/li&gt;
&lt;li&gt;relevance edge：Trigger Vertex-Metric Vertex&lt;/li&gt;
&lt;li&gt;diagnosis edge：Experience Vertex -Metric Vertex&lt;/li&gt;
&lt;li&gt;sysnonym edge：只出现在Tag Vertices-Tag Vertices之间，表示语义上同义，比如physical_read and disk_read; shared_pool and shared_buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以示例来分析运维经验图模型：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/af2763d6d88b.png" alt="image-20251215210049114" /&gt;&lt;/p&gt;
&lt;p&gt;LOG FILE SYNC有多种TAG，TAG跟Experience、metric、tool关联。能看出来关联性非常强，它代表了人类DBA对LOG FILE SYNC的理解和运维经验。&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%9b%be%e7%9a%84%e6%9e%84%e5%bb%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;手搓图是不靠谱的，现有的ML生成图可能生成没关系的关系，所以提出了半自动的图生成方案。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图的初始化：这一部分是手动生成的，根据规则来定义trigger vertices。trigger vertices一旦生成，其关联的metric vertex、experience vertex等会自动生成。这部分有点像人类DBA指导创建知识草图，总的框架不能动，不能生成一些稀奇古怪的东西。&lt;/li&gt;
&lt;li&gt;图的存放：就是放到Neo4J里；另外，不同的数据库类型通过tag来标记，这样很多知识是通用的，也避免了重复构建图。&lt;/li&gt;
&lt;li&gt;图的增强：生成更多的边&lt;/li&gt;
&lt;li&gt;图的更新：DBAIOps支持增量更新。这里的更新不仅指新增新的vertex，也包括去掉老的vertex&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%bc%82%e5%b8%b8%e6%a8%a1%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;metric
 &lt;div id="metric" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#metric" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;metric的来源有很多，包括运行信息（CPU %，吞吐等日常监控）、日志、trace等等，再加上相关性的差异，还需要从中取出关联性较强的metric。所以将metric分成了2类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;立即收集的metric：运行信息、日志、trace&lt;/li&gt;
&lt;li&gt;后续收集的metric：周期、delta等metric，需要的时候再生成，比如AWR/ASH数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在metric和异常相关性上，不同于基于基线的关联方式，DBAIOps采用每种异常都基于特定的metric组合。&lt;/p&gt;
&lt;p&gt;最后通过一个公式来判断是否确实发生异常：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/3693e91d7723.png" alt="image-20251214093339574" /&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%b8%a4%e9%98%b6%e6%ae%b5%e5%9b%be%e6%bc%94%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;数据库异常很少孤立发生，一个性能问题可能同时触发或恶化其他问题。然而，预构建的知识图谱中不同异常模型 (如 LOG_FILE_SYNC 和 REDO_ALLOCATION) 之间的连接往往松散，共享的经验片段稀疏且碎片化。这导致传统方法难以发现跨模型的复合根因，如 I/O 瓶颈与内存压力的组合问题。&lt;/p&gt;
&lt;p&gt;为解决这一挑战，DBAIOps 提出了自动 &amp;ldquo;图演化&amp;rdquo; 机制，动态发现并连接不同异常模型间的相关经验片段，使知识图谱从初始的稀疏结构逐步演化为密集互联的网络，从而支持更全面的根因分析。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;第一阶段-Graph Inference and Proximity Discovery (图推理与邻近发现)：通过图查询语言 (Cypher) 收集和聚合相关指标，基于可配置阈值遍历相关节点和边，构建关联网络。例如LOG_FILE_SYNC 延迟，从顶点出发，遍历最多 3 跳的关联节点。在 LOG_FILE_SYNC 和 REDO_ALLOCATION 模型间建立连接，因为它们都与 I/O 相关的并发问题有关。通过多次迭代，知识图谱逐渐演变为更密集的结构，使诊断能考虑更多潜在因素和复合原因。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二阶段-Adaptive Abnormal Metric Detection (自适应异常指标检测)：在图扩展路径上识别真正异常的指标。通过自适应检测函数（ADF），结合指标波动性、动态基线偏差等维度计算综合异常分数，依据异常评分结果，决定是否需要进一步扩展知识图谱结构，为后续 LLM 的根因推理筛选出精准的异常指标子集。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/313bde49387f.png" alt="image-20251214103841593" /&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%94%9f%e6%88%90%e5%88%86%e6%9e%90%e6%8a%a5%e5%91%8a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;图搞定后，就需要prompt喂给LLM来生成想要的报告，一个合理的prompt也可以提升报告的准确性。&lt;/p&gt;
&lt;p&gt;异象有5种成分，这5种成分作为prompt给LLM：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anomaly：异常描述（“CPU usage spiked to 95% at 16:00 on 2023-10-05”）&lt;/li&gt;
&lt;li&gt;Condition：异常触发条件（“exceeds 90% for &amp;gt;5 min”）&lt;/li&gt;
&lt;li&gt;Metrics&lt;/li&gt;
&lt;li&gt;Experience：提供正常负载值，或者最近的维护任务&lt;/li&gt;
&lt;li&gt;Output：描述报告的组成的。有异常验证（需要继续分析的）、根因分析、恢复方案、汇总、SQL文本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;自己的一点想法&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;最近的维护任务很有用，维护任务一般来说关联性是比较大的，故障分析也不是能是简单的技术分析。不过谁去更新这个维护任务、哪些要更新哪些不更新应该是问题。&lt;/p&gt;
&lt;p&gt;output中前几个都好理解，最后一个SQL文本可谓神来一笔。在生产环境中，抛开硬件故障，数据库的运行状态跟SQL是强相关的，我个人认为可以无脑抓SQL，抓出来再说因果关系的问题。从运维工作的角度来讲，故障都需要跟开发共同排查，那么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="#%e8%af%84%e4%bc%b0" 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/2f2ecc9b755b.png" alt="image-20251215082259815" /&gt;&lt;/p&gt;
&lt;p&gt;可以看出来很强了。特别要注意的是，DBAIOps特别强调了中型大模型的分析效果就已经很好了。这个还是比较重要的，DeepSeek-R1 671B裸跑就不差，但是成本不是一个级别的。&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%8c%91%e7%82%b9%e5%88%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;1.不能完全叫Ops，只是有故障分析功能。Ops内容是很多的，故障分析只是冰山一角。&lt;/p&gt;
&lt;p&gt;2.图的分类和图的示例对不上号。定义的tag vertex和edge跟示例的差别比较大。&lt;/p&gt;
&lt;p&gt;示例中的vertex作用很大，但是没有定义这些边的类型：tag vertex-tool vertex、tag vertex-experience vertex、tag vertex-metric vertex。而应该存在的边，看上去基本都没有，只有一个sysnonym edge。&lt;/p&gt;
&lt;p&gt;应该列举出来示例中没有说明的部分，不然看的云里雾里的。&lt;/p&gt;
&lt;p&gt;3.两阶段图演化的效果有点怪：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5fd6929e7dee.png" alt="image-20251214165952773" /&gt;&lt;/p&gt;
&lt;p&gt;w/o ADF代表没有第二阶段图演化（自适应异常指标检测）&lt;/p&gt;
&lt;p&gt;w/o ADF代表没有第一阶段图演化（图推理与邻近发现）&lt;/p&gt;
&lt;p&gt;w/o ADF代表两个阶段都没有的图演化&lt;/p&gt;
&lt;p&gt;这里少了两阶段都有的图演化，有的话就更能说明两阶段图演化的效果。&lt;/p&gt;
&lt;p&gt;4.根因有些少：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4e7faebf0b1a.png" alt="image-20251214114018609" /&gt;&lt;/p&gt;
&lt;p&gt;上面几个圈起来的应该是比较常见的（我只看了oracle、postgres），但是暂时没有这些根因。&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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;我个人非常喜欢的点：&lt;/p&gt;
&lt;p&gt;1.GraphRAG在故障诊断方面，应该会比vector RAG好。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/eddb311c9614.png" alt="image-20251215212534234" /&gt;&lt;/p&gt;
&lt;p&gt;（GraphRAG原始论文：&lt;a href="https://arxiv.org/pdf/2404.16130" target="_blank" rel="noreferrer"&gt;From Local to Global: A GraphRAG Approach to Query-Focused Summarization&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;SS代表vector RAG，TS代表源文本摘要，C0/C1/C2/C3代表不同知识粒度的GraphRAG。从这个图可以简单得出结论：GraphRAG更适合多预料复杂场景，多角度分析，但在精准度上其实不一定比vectorRAG好&lt;/p&gt;
&lt;p&gt;2.半自动的图生成方案&lt;/p&gt;
&lt;p&gt;图生成是半自动的，trigger vertex手搓，其他可以自动生成。例如LOG FILE SYNC就是trigger vertex。故障的入口确实可以做出明显的异常点，这就是入口，PG也是一样的，任何故障应该也是一样的，符合人类对故障的理解逻辑。&lt;/p&gt;
&lt;p&gt;.自动图演化&lt;/p&gt;
&lt;p&gt;加强某些vertex的关联性，是有意义的，Performance of DBAIOps** Variants表格可见一斑&lt;/p&gt;
&lt;p&gt;4.自动基线调整&lt;/p&gt;
&lt;p&gt;在《可观测性工程》中对AIOps有这么一段话：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;AI只有在存在清晰可辨的模式并且可以识别不断变化的基线来进行预测时才能提供帮助——目前还没有这种AIOps&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;DBAIOps在我的眼中&lt;/p&gt;
&lt;p&gt;清晰可辨的模式= DBAIOps中的图，它包括了故障模型、异常关系、监控数据和日志&lt;/p&gt;
&lt;p&gt;不断变化的基线= DBAIOps中的自适应异常指标检测&lt;/p&gt;
&lt;p&gt;总之，比随意chunk故障知识、拍一个基线、vector近似搜索的RAG模型要进步很多了。&lt;/p&gt;</content:encoded></item><item><title>我的年终总结2025</title><link>https://lastdba.com/2025/12/21/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932025/</link><pubDate>Sun, 21 Dec 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/12/21/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932025/</guid><description>&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;作为一个DBA，在问题分析方面我非常相信第一性原理与信息论。DBA需要非常了解这套系统，了解postgres，才能从原理上解释异象。比如上半年花了很多精力去了解linux内存，去探索内存问题的本质和解决方案。同时，今年在系统运维层面更进了一步，不再仅关注技术层面的问题和处理，而更关注提供解决方案，它应该包含postgres数据库技术维度、系统维度和管理维度的思考。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;作为一个DBA，在问题分析方面我非常相信第一性原理与信息论。DBA需要非常了解这套系统，了解postgres，才能从原理上解释异象。比如上半年花了很多精力去了解linux内存，去探索内存问题的本质和解决方案。同时，今年在系统运维层面更进了一步，不再仅关注技术层面的问题和处理，而更关注提供解决方案，它应该包含postgres数据库技术维度、系统维度和管理维度的思考。&lt;/p&gt;
&lt;p&gt;简单分类了一下云DBA的工作：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2e7e4042bd88.png" alt="image-20251221120908749" /&gt;&lt;/p&gt;
&lt;p&gt;很多Ops论文都只是说故障处理，实际上故障处理应该不到运维实际工作量的5%，而且无论是学术还是实际，anamaly ops本身效果也不好，所以我不是很看好AIOps能帮DBA大忙这件事。请注意DBA运用AIOps和DBA运用AI是两码事。&lt;/p&gt;
&lt;p&gt;其实这个图一般般，因为没有包含领导任务，领导任务肯定是大头&lt;/p&gt;
&lt;p&gt;然后看了下23、24年的年记，可以简单给出我这个dba的工作年度总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2023年全面学习postgres&lt;/li&gt;
&lt;li&gt;2024年全面运维postgres&lt;/li&gt;
&lt;li&gt;2025年负责1510情绪价值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;非常讽刺的是，去年有一个结论“dba在给领导们提供1510情绪价值”，今年就陷进这个结论实践了。多的也不想说，总之是很累，心力交瘁。希望明年会有改善。&lt;/p&gt;

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


&lt;img src="https://lastdba.com/img/csdn/710a408c1e3a.png" alt="image-20251220160932315" /&gt;&lt;/p&gt;
&lt;p&gt;今年比去年看的书更多了（从20+到30+本），反倒是写的什么读书笔记之类的更少了。写东西确实麻烦，很费精力，而我也更喜欢看书的感觉。今年看的书相比于去年，明显pg技术类的减少，技术综合类的增多，甚至开始看心理学、经济学和哲学。总之是狩猎更广，不是仅限于数据库本身了。同时小说也更少了，小说像零食一样，越发对此类没有营养的内容没兴趣。&lt;/p&gt;
&lt;p&gt;今年的书单总体分为IT系统类、经济学、科普类、心灵类、小说类，还是像去年一样&lt;strong&gt;凭个人喜好&lt;/strong&gt;排个先后顺序。&lt;/p&gt;
&lt;p&gt;IT系统类书单：&lt;/p&gt;
&lt;p&gt;1.《SRE Google运维解密》：DBA并不是SRE，不过其工作含有对系统稳定性的目标，这跟DBA是有类似之处的。本书中有些云环境或者管理方面的内容，确实获益匪浅，例如对SLA、系统工程、运维压力、工作琐事、角色轮换、“相信团队而不是相信某一个技术专家”等等内容，非常精彩。前段时间还听到DBRE&amp;ndash;Database Reliability Engineer这个概念，比DBA都符合我现在的工作定位。总之是一本好书，现代运维必读之书。&lt;/p&gt;
&lt;p&gt;.《奔跑吧 Linux内核 入门篇》：运维开源数据库，必须了解操作系统。我研究linux内存的书之一&lt;/p&gt;
&lt;p&gt;2.《深入理解Linux进程与内存》：我研究linux内存的书之一&lt;/p&gt;
&lt;p&gt;2.《深入理解Linux内核》：我研究linux内存的书之一&lt;/p&gt;
&lt;p&gt;5.《可观测性工程》：传统监控和传统运维的模式和缺陷，可观测性本质又是什么，还是比较有帮助的。&lt;/p&gt;
&lt;p&gt;经济学书单：&lt;/p&gt;
&lt;p&gt;《微观经济学》：神作，作者德隆·阿西莫格鲁。我理解为人生必读读物，这本书是我笔记做的最好的一本书。不仅了解经济，也进一步了解这个社会。里面有些观点我印象深刻，比如&lt;/p&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;企业的进入和退出是市场正常的信号，不代表紊乱&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;公平与效益的权衡是一个课题&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.《国家为什么会失败》：神作，作者德隆·阿西莫格鲁。一句话可以总结这本书：国家为什么成功？因为有破坏性创新。德隆·阿西莫格鲁是24年诺贝尔经济学得主，获奖理由是 &amp;ldquo;对制度如何形成以及如何影响繁荣的研究&amp;rdquo;。更难得的是，这本书相比于其他经济学著作更容易让人理解。经济学首推神作。&lt;/p&gt;
&lt;p&gt;3.《理性乐观派》：说是比肩《人类简史》，那肯定是差一截了。但是内容性不差，也更偏经济学。里面有些观点非常新颖，比如：&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;li&gt;收入越多会越幸福，这是事实&lt;/li&gt;
&lt;li&gt;贸易在社会地位中的提升，是因为海洋贸易的兴起。因为陆地贸易不稳定，非常容易被掠夺。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4.《股票大作手回忆录》：好像学到了什么好像又啥也没学到。好看还算是好看。&lt;/p&gt;
&lt;p&gt;.《博弈论》：说实话，我觉得一般。内容是不多的，也很浅显，主要是经济学老提到博弈论，所以就翻开评鉴一下。&lt;/p&gt;
&lt;p&gt;6.《国富论》：非常晦涩，不是给正常人看的，内容性非常强。亚当·斯密一定是个天才，难以想象是什么脑子写出来的。对我来说难度太高，没看完放弃了。&lt;/p&gt;
&lt;p&gt;科普类书单：&lt;/p&gt;
&lt;p&gt;1.《A BREIF HISTORY OF INTELLIGENCE》：神作，AI时代必读物，这本书被我翻到陈旧，到处都是笔记。解构人类的大脑，理解什么是智力，理解AI是怎么来的。我给满分！我现在只要看到一个动物，首先会想它是什么智力级别···&lt;/p&gt;
&lt;p&gt;2.《浪潮之巅》：作者吴军。每个IT工作者都应该看的一本书。讲述IT大公司的沉浮，你可以了解到ORACLE、GOOGLE、仙童、贝尔实验室、甚至融资方面的基础知识。每个公司都有自己的基因，这个基因几乎是不可改变的，也决定了公司的文化和特点。程序员必读。&lt;/p&gt;
&lt;p&gt;3.《纳瓦尔宝典》：有很多有用的观点，比如对边际效益的看法。还有更重要的是，里面推荐了我今年最喜欢的书之一——《微观经济学》。以及推荐了改变我习惯的冥想。&lt;/p&gt;
&lt;p&gt;4.《如何管理一家软件公司》：作者是弗兰克・斯洛特曼 (Frank Slootman)，一位带领三家软件公司 (ServiceNow、Data Domain、Snowflake) 成功实现 IPO 的硅谷传奇 CEO。很不错的书，从IT公司管理者的角度看待公司发展、员工管理、执行力、决策以及决策失误等等。非常推荐。&lt;/p&gt;
&lt;p&gt;5.《银发经济学》：作者大前研一。从日本老龄化问题窥探中国老龄化问题和机遇。天朝的人口结构隐患严重，差不多要到暴雷的时候了，在这个时代下，非常推荐一读。&lt;/p&gt;
&lt;p&gt;6.《第四次浪潮》：作者大前研一。主要是讲日本没有赶上IT科技浪潮，仍然是老工业在支撑国民经济，看上去有些嫉妒韩国和中国。我个人很喜欢作者直接喷首相的态度，哈哈。&lt;/p&gt;
&lt;p&gt;7.《清单革命》：讲解西医手术前的清单检查的必要性，看似简单的步骤可以极大的提升手术成功率。这本书对我的工作有很大的影响，我确实把清单这个概念带入了工作，我也把数据库运维当成一次外科手术，清单是提高手术成功率的简单又必要的手段。&lt;/p&gt;
&lt;p&gt;《人月神话》：“加人”不能使系统工程项目时间线性减少，但也不能通过这个简单的排斥“加人”，因为大型系统工程确实需要很多人协作完成。是不错的书，但是说程序员必读，感觉有点过了。&lt;/p&gt;
&lt;p&gt;9.《数学之美》：作者吴军。也挺不错的书，技术总有他的数学基础，这本书通俗易懂地讲述数学之美。&lt;/p&gt;
&lt;p&gt;10.《麦肯锡结构化思维》：任何问题都应该结构化拆解，我遇到新的问题我会这么思考。有用的书。&lt;/p&gt;
&lt;p&gt;11.《菊与刀》：几年前的囤货没有看所以掏出来看的。写一个二战后的老美对日本的看法，可以窥探一些日本的文化，比如改良的儒家文化，无“仁”，亏欠心理等等。有个缺点是有点太久远了，现在的日本很大程度上不是以前那个样子。&lt;/p&gt;
&lt;p&gt;12.《黑天鹅》：黑天鹅指没有预测到的奇异事件。黑天鹅事件总是会发生的，没有100%预测准确这种事情。同时里面还说到分类，我自己联想了一下《结构化思维》《the world I see》的内容，“人类理解事物的本质是对事务分类”，但是分类总会将一些东西分得尴尬甚至分不下去，黑天鹅事件从分类那一刻起就存在了。是一个值得注意的思考，比较有意思。&lt;/p&gt;
&lt;p&gt;13.《专业主义》：作者大前研一。非常一般，不推荐&lt;/p&gt;
&lt;p&gt;心灵类书单：&lt;/p&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.《悉达多》：不明所以，rubbish&lt;/p&gt;
&lt;p&gt;6.《生命之书》：纯心灵鸡汤，rubbish&lt;/p&gt;
&lt;p&gt;小说类书单：&lt;/p&gt;
&lt;p&gt;1.《局外人》：神作。难以描述的真实感，感觉自己就像个局外人。&lt;/p&gt;
&lt;p&gt;《yellow face》：很有趣的书，讲的是一个美国白人剽窃一个已故黄种人作家的未发布的作品去发布，甚至笔名都很chinese，当粉丝知道她是白人时，可以感受到有多尴尬。趣味性地探讨种族偏见，像看美剧一样神奇，高潮迭起引人入胜。非常推荐。&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.《撒旦探戈》：不明所以，诺贝尔文学奖亦有差距&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%8d%9a%e5%ae%a2%e5%92%8c%e5%85%ac%e4%bc%97%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;公众号的名字一直都很纠结，本来也没什么心思维护，就随便用了几个名字。今年看了个纪录片-最后的棒棒，感触颇多。其实DBA这个行业跟棒棒一样在发生巨变，所以干脆就改成“最后的DBA”了。这个名字还算朗朗上口，也能代表一些时代背景和哲思，看起来是个不错的名字。&lt;/p&gt;
&lt;p&gt;由于投入工作的时间很多，本来写东西的时间就不多，再加上今年的运维方式也在不断变化，我的作息怎么调整都调不出一个好的时间段安排，甚至最后投入了一些资金，自己的时间也没见增加，为此恼火了好一阵。现在回过头一看，今年才发了12篇文章，甚至上半年一篇都没有。&lt;/p&gt;
&lt;p&gt;很不满意。&amp;#x1f620;&lt;/p&gt;
&lt;p&gt;也不知道是水平高了还是系统真的稳定了，能深入研究的案例似乎变少了。不过这也不算什么大问题，今年还把解读论文当成一种文章类型，我自己感觉效果还可以，能学到不少东西，没有那么故步自封闭门造车。AI去解读论文肯定是快的，但是我自己感觉有2个问题&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否真的理解了。我感觉没有，跟自己去读一遍不是一个概念。自己去读不仅可以了解的更深入，还可以发现一些奇奇怪怪的细节&lt;/li&gt;
&lt;li&gt;水不了文章。如果我一个prompt就可以解读论文，那我感觉传播意义不大，现在不用AI的人应该没有了吧&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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;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%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;今年是忙碌的一年，有不好也有好的回忆，有很多重要的事情没有完成，明年应该做出较大的改变。写这个年记还是挺有意思的，回头看看前几年的自己在干嘛，也是有趣的事情。&lt;/p&gt;
&lt;p&gt;去年定的2025年OKR：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一些东西继续&amp;ndash;失败&lt;/li&gt;
&lt;li&gt;想想怎么做产出&amp;ndash;失败&lt;/li&gt;
&lt;li&gt;掌握一个其他赛道&amp;ndash;半成功&lt;/li&gt;
&lt;li&gt;PG···没想好还要怎么做&amp;ndash;失败&lt;/li&gt;
&lt;li&gt;想办法重拾健身&amp;ndash;失败&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2025年计划：&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;li&gt;探索DB AI OPS，明年向自己汇报&lt;/li&gt;
&lt;li&gt;向上管理，不可以投入过多时间到工作上&lt;/li&gt;
&lt;li&gt;假期旅游而不是卷&lt;/li&gt;
&lt;li&gt;读书不低于30本，不可仅关注数量&lt;/li&gt;
&lt;/ul&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>CXL和PolarDB-CXL</title><link>https://lastdba.com/2025/11/30/cxl%E5%92%8Cpolardb-cxl/</link><pubDate>Sun, 30 Nov 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/11/30/cxl%E5%92%8Cpolardb-cxl/</guid><description>&lt;p&gt;论文：Unlocking the Potential of CXL for Disaggregated Memory in Cloud-Native Databases&lt;/p&gt;
&lt;p&gt;SIGMOD best paper：&lt;a href="https://sigmod.org/sigmod-awards/sigmod-best-paper-award/" target="_blank" rel="noreferrer"&gt;https://sigmod.org/sigmod-awards/sigmod-best-paper-award/&lt;/a&gt;&lt;/p&gt;

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

&lt;h3 class="relative group"&gt;CXL的概念
 &lt;div id="cxl的概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cxl%e7%9a%84%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CXL&lt;/strong&gt;：开放的行业标准，由 CXL 联盟 (2019 年由英特尔、AMD、ARM 等科技巨头创立) 制定的高速互连规范。它代表了计算架构的演进方向。目前刚演进到CXL 4.0&lt;/p&gt;</description><content:encoded>&lt;p&gt;论文：Unlocking the Potential of CXL for Disaggregated Memory in Cloud-Native Databases&lt;/p&gt;
&lt;p&gt;SIGMOD best paper：&lt;a href="https://sigmod.org/sigmod-awards/sigmod-best-paper-award/" target="_blank" rel="noreferrer"&gt;https://sigmod.org/sigmod-awards/sigmod-best-paper-award/&lt;/a&gt;&lt;/p&gt;

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

&lt;h3 class="relative group"&gt;CXL的概念
 &lt;div id="cxl的概念" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cxl%e7%9a%84%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CXL&lt;/strong&gt;：开放的行业标准，由 CXL 联盟 (2019 年由英特尔、AMD、ARM 等科技巨头创立) 制定的高速互连规范。它代表了计算架构的演进方向。目前刚演进到CXL 4.0&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;特性&lt;/th&gt;
 &lt;th&gt;CXL 1.0/1.1&lt;/th&gt;
 &lt;th&gt;CXL 2.0&lt;/th&gt;
 &lt;th&gt;CXL 3.0/3.1&lt;/th&gt;
 &lt;th&gt;CXL 4.0 (最新)&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;发布时间&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;2019 年 3 月 / 9 月&lt;/td&gt;
 &lt;td&gt;2020 年 10 月&lt;/td&gt;
 &lt;td&gt;2022 年 8 月 / 2023 年 11 月&lt;/td&gt;
 &lt;td&gt;2025 年 11 月&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;基础协议&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;PCIe 5.0 (32 GT/s)&lt;/td&gt;
 &lt;td&gt;PCIe 5.0 (32 GT/s)&lt;/td&gt;
 &lt;td&gt;PCIe 6.0 (64 GT/s)&lt;/td&gt;
 &lt;td&gt;PCIe 7.0 (128 GT/s)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;最大带宽&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;1TB/s&lt;/td&gt;
 &lt;td&gt;1TB/s&lt;/td&gt;
 &lt;td&gt;2TB/s&lt;/td&gt;
 &lt;td&gt;4TB/s+&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;/td&gt;
 &lt;td&gt;单交换机 (≤32 节点)&lt;/td&gt;
 &lt;td&gt;多级 Fabric (4096 节点)&lt;/td&gt;
 &lt;td&gt;超大规模 Fabric&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;据我搜索的资料中，摘取两个比较影响深刻的对CXL的描述：&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;CXL switch&lt;/strong&gt;：是交换芯片，物理硬件。很多厂商在做工业化实现，论文中特指产商是XConn Tech的产品 &lt;a href="https://www.xconn-tech.com/products" target="_blank" rel="noreferrer"&gt;CXL 2.0 switch&lt;/a&gt;。需要注意的是，截止2025年11月22日，XConn这家只有CXL 2.0 switch，没有3.0的产品，市面上是有支持3.0+标准的交换芯片的产品&lt;a href="https://panmnesia.com/news/en/2025-11-13-switch-sample/" target="_blank" rel="noreferrer"&gt;panmnesia CXL 3.2 Fabric Switch&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;polarCXLMem&lt;/strong&gt;：据论文所说是“首个基于CXL-switch的分离式内存系统”。但是论文中提到“we leverage the world’s first CXL switch[50]”也就是特指Xconn tech CXL 2.0 switch，然后再提到“PolarCXLMem is the first CXL-switch-based disaggregated memory”。这句话可以理解为两种含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首个基于CXL switch的分离式内存系统&lt;/li&gt;
&lt;li&gt;首个基于Xconn tech CXL 2.0 switch的分离式内存系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;polardb-cxl&lt;/strong&gt;：其实论文中没有这个概念，但是行业在用这个词。这个词代表“integrate &lt;em&gt;PolarCXLMem&lt;/em&gt; into the multi-primary version of PolarDB,known as PolarDB-MP”，相当于“&lt;strong&gt;PolarDB-MP的CXL升级版&lt;/strong&gt;”。论文中反复使用这么长一段话，但是始终没有用polardb-cxl这个词。为了方便起见，本文中使用polardb-cxl这个词代表其本质含义。&lt;/p&gt;

&lt;h3 class="relative group"&gt;RDMA vs CXL
 &lt;div id="rdma-vs-cxl" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rdma-vs-cxl" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PolarDB-MP用的是RDMA架构，PolarDB-CXL是CXL架构：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fc236ee67755.png" alt="image-20251122115316339" /&gt;&lt;/p&gt;
&lt;p&gt;（https://medium.com/@anan.mirji/cxl-switch-vs-rdma-a-technical-comparison-for-high-performance-interconnects-6aaa031cde31）&lt;/p&gt;
&lt;p&gt;RDMA架构是跨主机的分布式互联架构，CXL架构这是单主机的扩展互联架构。&lt;/p&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;RDMA 架构&lt;/th&gt;
 &lt;th&gt;CXL 架构&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;单主机 + CXL 交换机的扩展架构&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;通信介质&lt;/td&gt;
 &lt;td&gt;网络（InfiniBand/RoCE）&lt;/td&gt;
 &lt;td&gt;PCIe 总线（CXL 基于 PCIe 物理层）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;核心组件&lt;/td&gt;
 &lt;td&gt;RDMA NIC（专用网卡）&lt;/td&gt;
 &lt;td&gt;CXL Controller、CXL Switch&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;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 class="relative group"&gt;CXL的优势
 &lt;div id="cxl的优势" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cxl%e7%9a%84%e4%bc%98%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CXL相较于RDMA的优势：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;低延迟：CXL通过PCIe连接主机或者设备上的内存；而RDMA 需要在InfiniBand与PCIe 之间进行协议接口转换&lt;/p&gt;
&lt;p&gt;指令支持：CXL提供了原生的 load/store指令，使CPU能像访问本地内存一样直接操作远程CXL设备内存；而RDMA需要从远端内存读到本地内存，在本地处理后再回写到远端内存。&lt;/p&gt;
&lt;p&gt;简化应用：RDMA需要特殊的接口和驱动，需要专业人员设计复杂的程序；而CXL提供透明的内存空间极大简化应用设计&lt;/p&gt;
&lt;p&gt;内存融合：CXL 3.0支持物理硬件级内存融合&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;polardb-mp存在的问题和CXL能提供的价值：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CXL说MP的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内存页是4-16K的，就算只需要很少的数据传输，也必须在本地内存和共享内存间传输数据，这导致了读写放大。&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;RDMA远好于TCP/IP，但在高并发下有 “门铃寄存器隐式竞争” 和 “缓存颠簸”问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库本身要维护共享内存&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CXL带来的好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消除“共享内存-本地内存”的层级内存结构，也消除了层级结构的维护消耗和读写放大问题。因为CXL load/store本地内存足够快，所以允许直接store所有的buffer pages&lt;/li&gt;
&lt;li&gt;以缓存行（64B）为最小CPU缓存和主存的传输单位，而不是polardb-MP的4K&lt;/li&gt;
&lt;li&gt;节约主存。主存（DRAM）的成本非常高，大约占服务器/机架成本的40-50%&lt;/li&gt;
&lt;li&gt;简化系统设计。在现有系统上最小化改造，对于商业数据库的稳定性来说很重要。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;PolarRecv&lt;/em&gt;：基于CXL做的立即恢复的系统。在数据库crash后，data和metadata都还在CXL上，可以直接在CXL memory上读到一致性状态，所以恢复非常快。（这看起来跟pg的page cache缓存可以帮助crash后快速启动有类似处）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DRAM vs RDMA vs CXL&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/66af810eb94e.png" alt="image-20251122155133782" /&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ae9cc24e5158.png" alt="image-20251122155109014" /&gt;&lt;/p&gt;
&lt;p&gt;在数据量较少时，RDMA比CXL延迟高不少，数据大一点RDMA的延迟就稍微好点。本地访问内存DRAM要略好于通过CXL访问。&lt;/p&gt;
&lt;p&gt;总体来说，CXL内存访问的延迟略高于DRAM但好于RDMA。&lt;/p&gt;
&lt;p&gt;对于CXL延迟高于DRAM，论文这样解释“database buffer pool operations are more sensitive to bandwidth than latency”，对于数据库内存来说，带宽比延迟重要。&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%87%aa%e7%a0%94%e6%9c%ba%e6%9e%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;自研的物理原型机架。左边的机架集成了两个支持 CXL 交换机的集群，每个集群均连接至内存设备与主机；右边的机架集成了1个CXL 交换机，连接至内存设备和主机。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/45333b6bf088.png" alt="image-20251122151718276" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;PolarCXLMem
 &lt;div id="polarcxlmem" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#polarcxlmem" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;CXL 2.0 switch支持内存池但驱动没有完全支持，所以PolarCXLMem还是设计了CXL的内存分配和使用，不是完全透明的。PolarCXLMem经过一些处理，将CXL memory分成了多租户的模式，不同的主机节点分配不同的CXL内存区域。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ddc3509d74d0.png" alt="image-20251123094443287" /&gt;&lt;/p&gt;
&lt;p&gt;PolarCXLMem的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;节点有各自的CXL内存区域，不同的节点不会交叠CXL内存&lt;/li&gt;
&lt;li&gt;buffer pool仍在数据库启动后就分配（由上图中的CXL mem manager分配），运行状态不会改变内存分配区&lt;/li&gt;
&lt;li&gt;cxl mem中的内存单位结构是block，block会存储page的数据和page的元数据，这些元数据包括：id代表页id，lock state代表页是否有被update锁定，prev/next是LRU双链，lsn为page的最新日志序列号。&lt;/li&gt;
&lt;li&gt;free list/in-use list用来做LRU的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;疑问：pg的pageheader有lsn、起始空闲空间指针、prune xid等等，polardb-cxl的页头又是什么结构呢？&lt;/em&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;PolarRecv
 &lt;div id="polarrecv" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#polarrecv" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PolarDB-MP是基于RDMA设计的，数据页在本地写入即可，分离式共享内存中没有最新版本的数据页。这导致主机crash后需要扫描和应用所有redo log文件（论文中说是redo不是wal）或一点点共享内存中的页。&lt;/p&gt;
&lt;p&gt;而CXL switch有独立的电源，即便主机宕机，最新的数据还在CXL内存中。所以PolarRecv利用这一点来极大的提高主机宕机后数据库的恢复速度。&lt;/p&gt;
&lt;p&gt;但是，虽然CXL switch内存透明又持久，crash后直接使用还是需要处理以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU list可能在crash时是不一致的&lt;/li&gt;
&lt;li&gt;B-tree SMO（B-tree结构变化），例如索引分裂时，可能在crash时是不一致的&lt;/li&gt;
&lt;li&gt;页在更新时crash，可能是不一致的&lt;/li&gt;
&lt;li&gt;redo log buffer用的本地DRAM，当redolog还没有刷盘时crash，CXL中的buffer pool中的page lsn可能大于redolog文件中的lsn，这直接违反了ARIES原则&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PolarRecv设计的对应策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用mutex来保护LRU结构，mutex锁的状态代表LRU是否在crash时被修改，如果是的话，LRU需要重建，如果不是则直接使用CXL内存中的LRU。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;B-tree SMO时会有一个mini-tranaction保护索引页，这个mini-tranaction是对应于page锁的两阶段锁。当mini-transaction提交时才会flush到redolog。所以在恢复过程中发现索引页有写锁，从redologs中恢复。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;polarcxl的读写锁是放在cxl内存中的。如果写锁还在，说明crash时update在中间状态没有完成。此时老实从redolog文件中读取page而不是在cxl内存中读取不一致的page。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;recovering过程中，首先会拿到redolog中最大LSN，然后检查CXL内存中page的锁和LSN，如果cxl内存中page的LSN大于最大LSN，那就用redolog中的信息去重建page而不是用CXL内存中版本。&lt;/p&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%86%85%e5%ad%98%e8%9e%8d%e5%90%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为PolarCXLMem是基于CXL 2.0 switch设计的，CXL 3.0才支持内存融合，所以还是要做内存融合的设计。因为每个节点的buffer pool都是隔离式地放在PolarCXLMem中，&lt;strong&gt;CXL 2.0的内存融合通过对DBP的元数据管理来实现，每个buffer pool都只存页的CXL内存地址而不是页本身&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d3b28a223927.png" alt="image-20251123142605871" /&gt;&lt;/p&gt;
&lt;p&gt;看懂上图需要注意区分CXL memory，dbp和本地buffer ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CXL memory是物理硬件，CXL mem本身&lt;/li&gt;
&lt;li&gt;dbp是CXL中开辟出来的区域用于管理内存融合服务&lt;/li&gt;
&lt;li&gt;本地 metadata buffer包含了本地buffer的元数据和CXL的部分&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外还需要了解，对于每个buffer pool中的page都有两个标志：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;invalid：其他节点写入页后，当前节点需要invalidate本地cpu cache&lt;/li&gt;
&lt;li&gt;removal：page从in-use list转移到free list，所有节点都要设置removal标志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内存融合page的访问流程：&lt;/p&gt;
&lt;p&gt;1.请求的页不在本地page metadata buffer中，&lt;/p&gt;
&lt;p&gt;1.1 从freelist中分配新的meta record，并通过rpc给内存融合服务提供invalid、removal地址&lt;/p&gt;
&lt;p&gt;请求的页在本地page metadata buffer中，&lt;/p&gt;
&lt;p&gt;2.1先检查removal flag，若removal被设置，代表内存融合服务已经回收了该page，需要通过RPC请求内存融合服务的新内存地址&lt;/p&gt;
&lt;p&gt;2.2然后检查invalid flag，invalid flag被设置，代表页被其他节点修改，需要invalidate cpu cache以确保一致性&lt;/p&gt;
&lt;p&gt;融合一致性：&lt;/p&gt;
&lt;p&gt;因为CXL 2.0没有内存融合，cpu cache不会被自动更新。polarcxl通过页级锁来实现多节点并发写入控制。&lt;/p&gt;
&lt;p&gt;节点读写page需要拿到读写锁。&lt;strong&gt;当一个节点正在写入page时，其他节点不能获得读写该page&lt;/strong&gt;。当节点写完后，还需要&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前节点将cpu cache &lt;em&gt;lflush&lt;/em&gt;到CXL mem中，以确保CXL mem是最新版本的page&lt;/li&gt;
&lt;li&gt;设置invalid flag，以确保其他节点不去读其cpu cache的老版本page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内存融合小节：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CXL 2.0本身支持不太完整的内存融合，导致数据库层还是需要设计内存融合方案。内存页通过CXL地址访问，而不是像RDMA方案一样本地/远程访问整个page。本地CPU cache需要数据库层来刷新以确保节点访问数据的一致性，这是硬性限制。这也导致了跨节点更新仍然是排他页级锁（RDMA方案也是排他页级锁）。&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%a7%e8%83%bd%e8%af%84%e4%bc%b0" 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%a4%9a%e8%8a%82%e7%82%b9%e8%af%bb%e5%86%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一个192 vC的主机上放12个实例进行的压测，对比RDMA（PolarDB-MP）和CXL（PolarDB-MP with PolarCXLMem）的性能：&lt;/p&gt;
&lt;p&gt;点查：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c5ac5a1f0d82.png" alt="image-20251124083738393" /&gt;&lt;/p&gt;
&lt;p&gt;范围查询：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/169bdabdbf3c.png" alt="image-20251125082404440" /&gt;&lt;/p&gt;
&lt;p&gt;读写：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/532e83b71906.png" alt="image-20251125082418710" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;点查：点查的读放大问题最严重，CXL的带宽消耗比RDMA小3-4倍。当节点达到3个时，RDMA的带宽已经被占满，再增加节点不会有任何带宽上的提升。&lt;/li&gt;
&lt;li&gt;范围查询：范围查询的读放大问题没有那么严重，只是在节点大于4时达到带宽上限11GB/s，而CXL还可以随节点线性增长。&lt;/li&gt;
&lt;li&gt;读写：表现与范围查询类似，只是差异再小一点&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;PolarRecv恢复时效
 &lt;div id="polarrecv恢复时效" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#polarrecv%e6%81%a2%e5%a4%8d%e6%97%b6%e6%95%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;vanilla指一般方案，应该是指类似pg从本地cache或disk中读取（也有可能是polar redo）&lt;/li&gt;
&lt;li&gt;RDMA-based指polardb-mp有些数据可以从分离式共享存储中读取&lt;/li&gt;
&lt;li&gt;PolarRecv指从大部分数据从CXL中继续读，少部分patial page需要从redo文件中恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6d0ae251efed.png" alt="image-20251125085711364" /&gt;&lt;/p&gt;
&lt;p&gt;论文中论述恢复时效其实分为2个阶段：起库/recovery和负载达到crash前的水平。只读不需要recovery，只要有数据就能起库承接负载。当有写入时，就需要做恢复，此时继续从CXL内存读数的优势就体现出来了。1分钟、2分钟、4分钟的恢复时效，还是有差距的，差距可能就是业务几乎无感和有感的区别。&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%e6%95%b0%e6%8d%ae%e6%9b%b4%e6%96%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;分布式数据库性能PK的焦点就是对共享数据的更新。在Polardb-mp性能暴打taurus-mm后，Polardb-cxl也暴打了Polardb-mp：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/30660f6b6fd5.png" alt="image-20251130164309249" /&gt;&lt;/p&gt;
&lt;p&gt;0%的 shared data的情况下，RDMA-based就访问local buffer就行了，Polardb-CXL只是把CXL当成内存池使用。即便如此，CXL-based还是性能更好，主要是之前说的，RDMA-based方案有读写放大和带宽上限问题。&lt;/p&gt;
&lt;p&gt;从上的性对比图可以看出来Polardb-CXL明显好于Polardb-MP，数据是非常清晰的。但是要注意，当shared data&amp;gt;60%时，Polardb-CXL性能提升不明显了，主要原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页级锁成为瓶颈&lt;/li&gt;
&lt;li&gt;随着锁竞争加剧，进程会进入sleep状态，频繁的上下文切换也加剧了资源争用&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;p&gt;PolarDB-CXL优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;消灭了RDMA的“本地-远程”层级内结构设计&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决了RDMA的读写放大问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供基于CXL的内存池&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PolarRecv基于CXL持久内存，数据库崩溃恢复速度更快&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;压测显示polardb-mp cxl性能优于polardb-MP RDMA&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PolarDB-CXL缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨节点更新仍然是页级锁，在共享数据更新的场景下，仍是性能瓶颈的主因&lt;/li&gt;
&lt;li&gt;CXL 2.0 switch看起来有点老了，在论文发表的时候已经有支持3.2的交换设备了，在2025年11月也发布CXL 4.0标准。可以预测未来应该有基于更新CXL标准的交换设备的数据库出现。&lt;/li&gt;
&lt;li&gt;论文质量其实没有MP这篇高，主要是围绕CXL 2.0 switch物理硬件做的解决方案，跟PoalrDB-MP论文中有大量的数据库层面的设计还是有区别的&lt;/li&gt;
&lt;/ul&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>论文精读|PolarDB-MP|2024 SIGMOD最佳工业论文</title><link>https://lastdba.com/2025/11/30/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BBpolardb-mp2024-sigmod%E6%9C%80%E4%BD%B3%E5%B7%A5%E4%B8%9A%E8%AE%BA%E6%96%87/</link><pubDate>Sun, 30 Nov 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/11/30/%E8%AE%BA%E6%96%87%E7%B2%BE%E8%AF%BBpolardb-mp2024-sigmod%E6%9C%80%E4%BD%B3%E5%B7%A5%E4%B8%9A%E8%AE%BA%E6%96%87/</guid><description>&lt;p&gt;论文：PolarDB-MP: A Multi-Primary Cloud-Native Database via Disaggregated Shared Memory&lt;/p&gt;
&lt;p&gt;SIGMOD best paper：https://sigmod.org/sigmod-awards/sigmod-best-paper-award/&lt;/p&gt;</description><content:encoded>&lt;p&gt;论文：PolarDB-MP: A Multi-Primary Cloud-Native Database via Disaggregated Shared Memory&lt;/p&gt;
&lt;p&gt;SIGMOD best paper：https://sigmod.org/sigmod-awards/sigmod-best-paper-award/&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%89%8d%e8%a8%80%e5%92%8c%e6%91%98%e8%a6%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;开篇提出问题：主从库的写入吞吐受主库限制。shared-nothing架构是可扩展的多主集群，可以解决单主受限问题，但是该架构因分布式事务的开销而出现性能瓶颈。最近基于共享存储的云原生多主数据库出现，但该架构在高冲突场景下，有冲突解决代价高和数据融合效率低的问题。&lt;/p&gt;
&lt;p&gt;所以，提出的问题的是：单主主从架构、shared-nothing架构、共享存储云原生多主架构，都有各自的问题。&lt;/p&gt;
&lt;p&gt;本篇论文提议PolarDB-MP，它是结合了分离式共享内存与共享存储的新型多主云原生数据库。（an innovative multi-primary cloud-native database ，多主云原生数据库已经有了，所以得是新型）。&lt;/p&gt;
&lt;p&gt;PolarDB-MP的基本特点：&lt;/p&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;共享存储：PolarStore and PolarFS，或者其他兼容性共享存储方案&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;strong&gt;RDMA&lt;/strong&gt;远程直接内存访问实现低延迟通信&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LLSN&lt;/strong&gt;（局部逻辑序列号，Local Logical Sequence Number）。用于为不同节点生成的预写日志建立部分有序关系（partial order）**，**并配合定制化恢复策略，确保系统在异常恢复时的一致性与高效性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;核心组件&lt;strong&gt;PMFS&lt;/strong&gt;（Polar Multi-Primary Fusion Server多主融合服务器）负责：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;Transaction Fusion（事务融合）——负责事务排序与可见性管理&lt;/li&gt;
&lt;li&gt;Buffer Fusion（缓冲区融合） —— 提供分布式共享缓冲机制&lt;/li&gt;
&lt;li&gt;Lock Fusion（锁融合）—— 用于跨节点并发控制&lt;/li&gt;
&lt;/ul&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%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;分类主要是为了看清polardb-mp的历史位置，也是为了理解”第一的定语“:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PolarDB-MP is the first multi-primary cloud-native database that utilizes disaggregated shared memory and shared storage for transaction coordination and buffer fusion&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/3532d59aa524.png" alt="image-20251109213814089" /&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%ab%9e%e5%93%81%e9%bb%91%e7%82%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;shared-nothing产品：对于这类产品没有一个个提黑点，只是一句话带过：事务在跨多分区访问时，分布式事物需要显著的额外开销。&lt;/p&gt;
&lt;p&gt;oracle：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;昂贵的分布式锁管理&lt;/li&gt;
&lt;li&gt;昂贵的网络开销&lt;/li&gt;
&lt;li&gt;比较依赖精致的机器（alien tech）&lt;/li&gt;
&lt;li&gt;难以上云，或者上云后比云原生数据库的TCO成本（包含维护、人力成本）更高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AWS Aurora-MM：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采用乐观事物模型，事务冲突时有较高的事物中止率&lt;/li&gt;
&lt;li&gt;某些场景下，4节点吞吐低于单节点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;华为 Taurus-MM：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;悲观事物模型。依赖页存储和日志重放来保证缓存一致性，在并发控制和数据同步方面存在较高的开销。&lt;/li&gt;
&lt;li&gt;50% shared data 读写场景下，8节点只有1.5倍的单节点性能提升&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;oracle这里的黑点主要是看着有道理的口嗨，Aurora-MM和Taurus-MM是有原厂商引述的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Aurora-MM “某些场景下，4节点吞吐低于单节点”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Taurus-MM “50% shared data 读写场景下，8节点只有1.5倍的单节点性能提升”&lt;/p&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="#%e4%ba%8b%e5%8a%a1%e8%9e%8d%e5%90%88" 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%e8%9e%8d%e5%90%88%e6%a6%82%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;多主如何保证一致性数据视图？&lt;/p&gt;
&lt;p&gt;快照隔离是常见的MVCC实现方式。快照隔离有一个特性是，查询或者事务必须在执行期间保持自己的一致性数据视图（consistent data view）。但是在多主架构中，因为远端的数据更新，本地无法保证一致性数据视图。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，一般的多主共享存储架构，会引入全局事务的机制（AuroraMM or Taurus-MM）。而在PolarDB-MP中提出了创新技术&amp;ndash;PMFS中的事务融合技术。&lt;strong&gt;每个节点只维护本地事务信息，通过RDMA被其他节点访问&lt;/strong&gt;。与全局事务相反，事务融合是去中心化的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;本地事物和TIT表
 &lt;div id="本地事物和tit表" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e4%ba%8b%e7%89%a9%e5%92%8ctit%e8%a1%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;polardb-mp的每个节点都会有一小部分内存来存储本地的事务信息（可以被其他节点通过RDMA访问）。这些本地事务信息存储在transaction Information Table (TIT)中。&lt;/p&gt;
&lt;p&gt;TIT表的内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务对象指针&lt;/li&gt;
&lt;li&gt;由全局时间戳协调器(TSO)分配的事务提交时间戳CTS（commit timestamp）&lt;/li&gt;
&lt;li&gt;version，代表同一slot中的不同事务（&lt;em&gt;事务对象指针不是指向一个事务？？？&lt;/em&gt;）&lt;/li&gt;
&lt;li&gt;ref，标识这个事物是否被其他事物等待释放锁（应该是Plock或者Rlock）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/90641c3618d1.png" alt="image-20251101131556184" /&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%e6%98%af%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;当事务开始时，本地事务id(应该就是txid了）会被分配，TIT slot会存放这个事务对象指针、ref初始化为0、CTS初始化为&lt;code&gt;CSN_INIT&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Polardb-mp用全局事务ID标识一个事务，全局事务ID=（node_id, trx_id, slot_id, version）。全局事务ID是不包含CTS的，如果要知道事务的提交顺序，比如构建事务可见性视图时，就需要通过全局事物ID，经过RDMA，去目标节点找到CTS（类似pg中的&lt;code&gt;pg_xact_commit_timestamp()&lt;/code&gt;函数通过事务id从本地文件找到对应的事务提交时间）。&lt;/p&gt;
&lt;p&gt;如果trx_id是pg中事务ID的话，那么node_id,trx_id就可以标识事务的全局唯一性了，或者node_id,slot_id,version在某种程度上也可以（未复用slot id的情况下，比如某个时刻可以标识唯一事物id），当然多出来的信息组合起来也唯一。毕竟这些信息是polardb-mp实现事务融合的关键。&lt;/p&gt;
&lt;p&gt;每个事务都会通过全局事务ID和CTS来构造可见性视图。可见性视图的概念跟pg是一致的，当前read view可读read view前已提交事务的数据行，且为最新版本行。&lt;/p&gt;

&lt;h3 class="relative group"&gt;访问远端的CTS
 &lt;div id="访问远端的cts" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%bf%e9%97%ae%e8%bf%9c%e7%ab%af%e7%9a%84cts" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为CTS在本地（TIT or本地文件系统上）的缘故，所以获得读取事务的CTS是一个有意思活：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/41db536b2114.png" alt="image-20251101153437311" /&gt;&lt;/p&gt;
&lt;p&gt;1.1 如果一个行的CTS是CSN_INIT/CTS_INIT，即事务仍然活跃，那么返回最大CTS表示其对所有事务不可见，除了自己。&lt;/p&gt;
&lt;p&gt;1.如果一个行的CTS不是CSN_INIT/CTS_INIT，即事务已提交，且在本地的TIT中，那么直接返回CTS&lt;/p&gt;
&lt;p&gt;2.如果一个行没有CTS，通过行的g_trx_id获取CTS&lt;/p&gt;
&lt;p&gt;2.1 如果事务属于本地节点（ g_trx_id有node id），那么从本地文件系统读到本地TIT&lt;/p&gt;
&lt;p&gt;2.2 如果事务不属于本地节点，那么从远端文件系统读到远端TIT，通过RDMA去访问&lt;/p&gt;
&lt;p&gt;3.1 如果slot.version != g_trx_id.version，那么事务一定提交了，那么该行一定被所有事务可见（准确来说应该是一定被当前及以后的read view可见，但是&lt;em&gt;理论上&lt;/em&gt;TIT slot不会把活动事务访问的row给刷下去，所以是所有事务可见），返回最小CTS表示其对所有事务可见&lt;/p&gt;
&lt;p&gt;3.2 如果slot.version = g_trx_id.version，参考1.1、1.2&lt;/p&gt;
&lt;p&gt;polardb-mp的事务可见性理念跟pg很相似，只是pg用的是txid而不是CTS表示事务新旧，也不需要考虑远程访问。&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%a1%8c%e6%9b%b4%e6%96%b0%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;polardb-mp更新行的时候，除了更新数据本身，还需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;更新行的全局事务ID（g_trx_id）（如果是行上更新，那么就改造了pg的行头）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新行的CTS。（这里没有说是行头还是文件系统，如果类似pg，那么应该是文件系统上的&lt;code&gt;commit_ts&lt;/code&gt;目录上。polar未证实）&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="#%e6%8f%90%e9%97%ae%e4%ba%8b%e5%8a%a1%e8%9e%8d%e5%90%88%e6%b2%a1%e7%9c%8b%e6%87%82%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;g_trx_id是行的元数据，写入磁盘的。如果节点减加，需要更新数据行g_trx_id中的node_id吗？如果不需要，下次读取出来应该加载到哪个节点？&lt;/p&gt;
&lt;p&gt;一个新行的CTS存储在本地节点A，如果一个其他节点B又更新了这个行，新的CTS在A还是B节点？&lt;/p&gt;
&lt;p&gt;assigned a read view, which consists of its own g_trx_id and the current CTS。只读事务在构建读视图时，也会分配g_trx_id吗？&lt;/p&gt;
&lt;p&gt;毫无疑问，类似&lt;code&gt;track_commit_timestamp&lt;/code&gt;参数一定是强制打开的&lt;/p&gt;
&lt;p&gt;如果有大量的写在A节点，读在B节点，B节点的读会通过RDMA访问A节点的TIT对应的数据，是不是会产生大量的网络IO？那么是不是需要在考虑读写分离时，或者多节点写入和读取时，应该考虑这个问题？不知道原文能不能回答这个问题&amp;ndash;“多主架构天生就需要在节点间同步大量的数据和消息，以支撑关联多节点的并发访问。随着网络技术的发展（InfiniBand，RDMA）和商业化落地，网络瓶颈变得不那么重要。”&lt;/p&gt;
&lt;p&gt;全局时间戳可能成为分布式系统的瓶颈，PolarDB-SCC是基于共享存储的时间戳，看上去性能不错。时间有限，先按下再说。&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%9e%8d%e5%90%88" 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%86%85%e5%ad%98%e8%9e%8d%e5%90%88%e5%bc%95%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;polardb-mp的每个节点都可以更新任何数据页，这会导致大量的数据转移。Buffer Fusion’s distributed buffer pool (DBP)就是为了解决这个问题。每个节点都有本地内存池LBP，属于DBP的子集。&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%e8%9e%8d%e5%90%88%e6%98%af%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;LBP有两个新的东西用以存放页的元数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;valid：是否被其他节点更新&lt;/li&gt;
&lt;li&gt;r_addr：指针，指向DBP上的page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/652bf5e74943.png" alt="image-20251102105723909" /&gt;&lt;/p&gt;
&lt;p&gt;从LBP访问page时，当前节点需要先检查page是否是有效的，如果无效，需要通过r_addr去访问dbp。当dbp中存放page的新的版本后，内存融合会让所有远端的page失效。在LBP中，脏page会在后台周期性地或释放Plock锁后刷到DBP中。&lt;/p&gt;
&lt;p&gt;page访问的步骤：&lt;/p&gt;
&lt;p&gt;1.1 如果page在LBP且valid，直接访问。&lt;/p&gt;
&lt;p&gt;1.2 如果page在LBP且invalid，经过RDMA访问DBP&lt;/p&gt;
&lt;p&gt;2 如果page既不在LBP也不在DBP，从共享存储读取&lt;/p&gt;
&lt;p&gt;3 page从一个node加载到LBP，并注册到DBP中&lt;/p&gt;
&lt;p&gt;PolarDB内存融合的关键组件是分离式共享内存。看上去是一个/组物理硬件或者其上集成后的完整组件，游离于计算节点之外。这部分跟传统分布式系统的内存有很大的不同。&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="#%e6%8f%90%e9%97%ae%e5%86%85%e5%ad%98%e8%9e%8d%e5%90%88%e6%b2%a1%e7%9c%8b%e6%87%82%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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%94%81%e8%9e%8d%e5%90%88" 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%94%81%e8%9e%8d%e5%90%88%e4%b8%ad%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;内存融合是为了解决节点怎么访问远端数据，锁融合是为了解决并发访问控制。&lt;/p&gt;
&lt;p&gt;内存融合有两种锁：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;page-locking (PLock)：类似latch，控制原子访问和内部结构一致性。单节点page访问没有Plock。&lt;/li&gt;
&lt;li&gt;row-locking (RLock)：负责跨节点的事务控制，遵循两阶段锁协议&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;PLock访问流程
 &lt;div id="plock访问流程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#plock%e8%ae%bf%e9%97%ae%e6%b5%81%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;（论文没有说锁融合发生在哪，因为Plock是页上的栓锁，页的融合发生在共享内存上，所以我先假设锁融合也发生在共享内存上，因为这样容易理解一点）&lt;/p&gt;
&lt;p&gt;1 在更新/读取page前，通过&lt;em&gt;本地锁管理器&lt;/em&gt;检查本地节点是已持有对应的X/S Plock（或更高级别的锁）&lt;/p&gt;
&lt;p&gt;1.1如果有，原地执行操作&lt;/p&gt;
&lt;p&gt;1.2 如果没有，通过Lock fusion拿到PLock&lt;/p&gt;
&lt;p&gt;2 锁融合在响应前先检查冲突，如果冲突存在则请求等待&lt;/p&gt;
&lt;p&gt;3 当PLock被一个节点释放，会通知锁融合，锁融合更新Plock的状态，并通知其他节点继续执行自己的操作&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/92aa2082d68f.png" alt="image-20251102142359091" /&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Plock lazy releasing
 &lt;div id="plock-lazy-releasing" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#plock-lazy-releasing" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;根据上面PLock访问流程，一个Plock在本地执行完操作后会被立即释放。这可能不是最优解，根据时间局部性原理——“一个数据或指令在某一时刻被访问，那么在短期内，它很可能会被再次访问”。lazy releasing就是为了最小化Plock锁的RPC访问负载。&lt;/p&gt;
&lt;p&gt;原理很简单，Plock在本地节点使用后不会被立即释放，而是等ref为0时才释放。&lt;/p&gt;
&lt;p&gt;当其他节点需要PLock时，锁融合还会发送谈判信息干预本地节点一直持有锁，本地必须与锁融合通信而不是自主处理PLock。锁融合采用“先进先出”的策略解决跨节点锁归属权问题，同样直到本地节点的ref=0时，其他节点才可以拿到锁。&lt;/p&gt;
&lt;p&gt;lazy releasing是有效的分布式锁解决方案，为了平衡本地锁优化和全局锁分配。&lt;/p&gt;

&lt;h3 class="relative group"&gt;RLock概述
 &lt;div id="rlock概述" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rlock%e6%a6%82%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;RLock是通过全局事务ID来判断的（跟pg类似）。根据事务融合的内容，全局事务ID包含了节点id、事务id、slot id、version。所以，本地节点读取行时直接就可以拿到行上所需要的锁信息，知道锁在哪（node id），知道锁是否活跃。&lt;/p&gt;
&lt;p&gt;判断事务活跃也有2个好玩的点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从事务融合访问远端的CTS的流程来看，事物的CTS是有效值或事物在TIT中属于同一slot但不是同一version，说明事物肯定提交了，所以不需要再检查是否活跃。源事务不活跃当然就不等待锁，直接运行。&lt;/li&gt;
&lt;li&gt;pg中会有最小活跃事物ID的概念，在polardb-mp中也存在。如果行上的事务ID小于全局的最小活跃事务ID，那么源事务肯定也提交（或回滚）了。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;Rlock是如何进行的
 &lt;div id="rlock是如何进行的" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rlock%e6%98%af%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;本地行本地处理即可，只有冲突的时候会在锁融合中处理，跨节点行锁才需要RLock。”The transaction ID in the row functions as a lock indicator. So this protocol only supports exclusive (X) lock. The shared (S) lock on a row is not supported in PolarDB-MP, but it’s acceptable“ ，真冲突的排他锁才需要RLock，共享锁不需要RLock。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a84d705b09b8.png" alt="image-20251102155613001" /&gt;&lt;/p&gt;
&lt;p&gt;1 T30从共享存储中读取行，从行的元数据（g_trx_id)就可以知道事物活跃且事务在哪个节点&lt;/p&gt;
&lt;p&gt;2 T30远程调整T10的事物ref&lt;/p&gt;
&lt;p&gt;3 T30发送等待状态给锁融合服务&lt;/p&gt;
&lt;p&gt;4 锁融合添加等待信息到wait info table中&lt;/p&gt;
&lt;p&gt;5 T10执行结束，通知Lock Fusion&lt;/p&gt;
&lt;p&gt;6 Lock Fusion检查wait info table，然后通知T30可以继续执行了&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%8f%90%e9%97%ae%e9%94%81%e8%9e%8d%e5%90%88%e6%b2%a1%e7%9c%8b%e6%87%82%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;“when attempting to update a row, it must already hold an X PLock lock on the page containing the row”&lt;/p&gt;
&lt;p&gt;update还要持有page的PLock排他锁，也就是说同一page上的update是相互阻塞的，这会影响并发吧？本地应该不会有这种行为，pg是没有update场景的page排他的。&lt;/p&gt;
&lt;p&gt;在Logs ordering and recovery章节有这么两句话：“Thanks to the PLock design, only one transaction can update a page at a time&amp;quot;，“When a page is updated across two nodes, one node pushes its updated page to the DBP before releasing the PLock,allowing the next node to retrieve it from the DBP.”&lt;/p&gt;
&lt;p&gt;是的，在&lt;strong&gt;跨节点&lt;/strong&gt;数据更新时，有页级排他锁。&lt;/p&gt;

&lt;h2 class="relative group"&gt;PMFS小结（锐评）
 &lt;div id="pmfs小结锐评" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pmfs%e5%b0%8f%e7%bb%93%e9%94%90%e8%af%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PMFS（Polar Multi-Primary Fusion Server）是PolarDB-MP多主分布式系统实现的核心组件。其中，&lt;strong&gt;全局事务ID&lt;/strong&gt;设计巧妙，它转化了pg的事务ID为包含节点信息、事务id和事务融合中的slot和version信息并放在行头。这样做有几个好处：&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;li&gt;利用最小活动事务以减少冲突判断&lt;/li&gt;
&lt;li&gt;利用全局事务ID信息，实现分布式获取事务提交时间CTS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PMFS中的内存融合和锁融合看上去高度依赖共享内存组件&lt;/li&gt;
&lt;li&gt;RDMA的应用时刻存在&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%97%a5%e5%bf%97%e7%9a%84%e9%a1%ba%e5%ba%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;partial order
 &lt;div id="partial-order" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#partial-order" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;首先，wal在每个节点上都生成，且不需要任何并发控制机制，各自往共享存储中写。每个节点的LSN对于各自的节点而言是顺序的，但是多节点就不能体现wal记录在全局的顺序性。&lt;/p&gt;
&lt;p&gt;但是，需要在写入时体现wal记录的全局顺序吗？&lt;/p&gt;
&lt;p&gt;从论文来看，大部分情况是不需要的。&lt;/p&gt;
&lt;p&gt;只有1种情况需要保证写入时的全局顺序性，那就是跨节点更新同一个page时。&lt;/p&gt;
&lt;p&gt;但是，根据PMFS锁融合机制，跨节点更新同一page是排他的。锁融合就可以保证跨节点page更新的顺序了。&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%81%a2%e5%a4%8d%e7%9a%84%e9%a1%ba%e5%ba%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于跨节点写入的LLSN来自多个节点很可能不是顺序的，恢复时就需要按顺序进行恢复。全量读取wal记录再按LLSN排序是一个简单的方案，但是大量的排序非常消耗资源。&lt;/p&gt;
&lt;p&gt;polardb-mp提出了分段排序LLSN，每段称为chunk，chunk的边界称为LLSN bound。polardb-mp可保证LLSN bound一定小于下一个bound，然后在chunk内排序LLSN即可。&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%8f%90%e9%97%ae%e6%97%a5%e5%bf%97%e7%9a%84%e9%a1%ba%e5%ba%8f%e6%b2%a1%e7%9c%8b%e6%87%82%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;”utilizing redo (write-ahead) logs for data recovery and undo logs for rolling back uncommitted changes“&lt;/p&gt;
&lt;p&gt;polardb-mp有undo日志文件？这个undo是干嘛的？&lt;/p&gt;
&lt;p&gt;LLSN没有看出来有什么特别的，论文也没有详细说明它的结构，LSN看上去都够了，maybe全局事务id那有些区别。&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%af%84%e4%bc%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;只读都是本地的，所以加节点吞吐提升是线性的。如果读写/只写的数据都分区得好，不跨节点，也几乎是线性的。&lt;/p&gt;
&lt;p&gt;问题就在于读写/只写节点间共享数据的情况，非常考验分布式数据库的性能。&lt;/p&gt;
&lt;p&gt;论文直接拿华为的taurus-mm来对比。结论就是：polardb跨多节点写数据性能确实要好不少。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/eec82fe8cb39.png" alt="image-20251109212445723" /&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%b9%e6%af%9b%e7%b4%a2%e7%96%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;文章有2个地方提到Taurus-MM在8节点共享数据下的性能提升，但是数据有歧义：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The eight-node cluster only improves
the throughput by 1.8× compared to the single-node version in the
read-write workload with 50% shared data.&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;the throughput of Taurus-MM ’s eight-node cluster is approximately 1.8× that
of a single node under the SysBench write-only workload with 30%
shared data, illustrating the trade-offs and challenges in optimizing
multi-primary cloud databases&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;一会30% shared data，一会50% shared data，不是很严谨。原文&lt;a href="https://www.vldb.org/pvldb/vol16/p3488-depoutovitch.pdf" target="_blank" rel="noreferrer"&gt;Taurus MM&lt;/a&gt;是50%：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/34c0ec5e940b.png" alt="image-20251025162117902" /&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;p&gt;好像没什么好总结的，看章节&lt;em&gt;前言和摘要&lt;/em&gt;和&lt;em&gt;PMFS小结&lt;/em&gt; 就行。&lt;/p&gt;</content:encoded></item><item><title>案例-从distinct不准确到DISTINCT的计算原理</title><link>https://lastdba.com/2025/10/19/%E6%A1%88%E4%BE%8B-%E4%BB%8Edistinct%E4%B8%8D%E5%87%86%E7%A1%AE%E5%88%B0distinct%E7%9A%84%E8%AE%A1%E7%AE%97%E5%8E%9F%E7%90%86/</link><pubDate>Sun, 19 Oct 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/10/19/%E6%A1%88%E4%BE%8B-%E4%BB%8Edistinct%E4%B8%8D%E5%87%86%E7%A1%AE%E5%88%B0distinct%E7%9A%84%E8%AE%A1%E7%AE%97%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;统计信息的n_distinct不准确&lt;/p&gt;
&lt;p&gt;这个问题在多个库中出现，例如：&lt;/p&gt;
&lt;p&gt;表有2亿行数据，真实DISTINCT有800w，统计信息中的DISTINCT只有4w。&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;统计信息的n_distinct不准确&lt;/p&gt;
&lt;p&gt;这个问题在多个库中出现，例如：&lt;/p&gt;
&lt;p&gt;表有2亿行数据，真实DISTINCT有800w，统计信息中的DISTINCT只有4w。&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="#%e9%87%87%e6%a0%b7%e6%a8%a1%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7e0b33a60cf4.png" alt="备库是否有自己的统计信息？ · PostgreSQL学徒" /&gt;&lt;/p&gt;
&lt;p&gt;默认default_statistics_target=100，即采集30000 pages中的30000行数据。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt; tablzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;: analyzing &lt;span style="color:#e6db74"&gt;&amp;#34;public.tablzl1&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;: do_analyze_rel, &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;332&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;tablzl1&amp;#34;&lt;/span&gt;: scanned &lt;span style="color:#ae81ff"&gt;30000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22963751&lt;/span&gt; pages, containing &lt;span style="color:#ae81ff"&gt;1061942&lt;/span&gt; live &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3953&lt;/span&gt; dead &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;30000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; sample, &lt;span style="color:#ae81ff"&gt;812872389&lt;/span&gt; estimated total &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:#66d9ef"&gt;LOCATION&lt;/span&gt;: acquire_sample_rows, &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1340&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;ldquo;scanned 30000&amp;rdquo; 和 &amp;ldquo;30000 rows in sample&amp;rdquo;&lt;/p&gt;

&lt;h3 class="relative group"&gt;distinct预估算法
 &lt;div id="distinct预估算法" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#distinct%e9%a2%84%e4%bc%b0%e7%ae%97%e6%b3%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;distinct的预估算法&lt;code&gt;analyze.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;/*----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * Estimate the number of distinct values using the estimator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * proposed by Haas and Stokes in IBM Research Report RJ 10025:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 *		n*d / (n - f1 + f1*n/N)
&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 f1 is the number of distinct values that occurred
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * exactly once in our sample of n rows (from a total of N),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * and d is the total number of distinct values in the sample.
&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 is their Duj1 estimator; the other estimators they
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * recommend are considerably more complex, and are numerically
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * very unstable when n is much smaller than N.
&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;			 * In this calculation, we consider only non-nulls. We used 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;			 * include rows with null values in the n and N counts, but 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;			 * leads to inaccurate answers in columns with many nulls, 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;			 * it&amp;#39;s intuitively bogus anyway considering the desired result 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;			 * the number of distinct non-null values.
&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 assume (not very reliably!) that all the multiply-occurring
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * values are reflected in the final track[] list, and the other
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * nonnull values all appeared but once. (XXX this usually
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * results in a drastic overestimate of ndistinct. Can we 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;			 * any better?)
&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;int&lt;/span&gt;			f1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nonnull_cnt &lt;span style="color:#f92672"&gt;-&lt;/span&gt; summultiple;
&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;			d &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; nmultiple;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;		n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; samplerows &lt;span style="color:#f92672"&gt;-&lt;/span&gt; null_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;		N &lt;span style="color:#f92672"&gt;=&lt;/span&gt; totalrows &lt;span style="color:#f92672"&gt;*&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; stats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;stanullfrac);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;		stadistinct;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;n*d / (n - f1 + f1*n/N)&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt; = 样本行数（扫描的行数）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt; = 样本中发现的distinct值的数量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f1&lt;/code&gt; = 样本中只出现一次值的数量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt; = 表的总行数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;算法论文：&lt;a href="https://hugepdf.com/download/download-extended-version-of-this-paper_pdf" target="_blank" rel="noreferrer"&gt;https://hugepdf.com/download/download-extended-version-of-this-paper_pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;论文看起来比较费劲，下面做一些假设来理解这个disticnt算法：&lt;/p&gt;
&lt;p&gt;1.假设全是出现一次值，且表很大n&amp;laquo;N，即f1=d，n/N=0&lt;/p&gt;
&lt;p&gt;&lt;code&gt;d*d / (d - d + d*0)=d*2/0&lt;/code&gt;， 这应该是-1了.&lt;/p&gt;
&lt;p&gt;2.假设全是出现一次值，且表很小n=N，即f1=d，n/N=1&lt;/p&gt;
&lt;p&gt;&lt;code&gt;n*d / (n - d + d*1)=d&lt;/code&gt;，即采集的distinct数，也等于采集的行数&lt;/p&gt;
&lt;p&gt;3.假设采集样本中没有只出现一次值，即f1=0，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;n*d / (n - f1 + f1*n/N)=n*d / (n)=n*d / (n)=d&lt;/code&gt; ，也就是采样中的distinct数.&lt;/p&gt;
&lt;p&gt;如果一个列均是插入几条同样的值，然后再插入几条同样的值，比如：&lt;/p&gt;
&lt;p&gt;11,2,2,2,2,3,3,3,..&lt;/p&gt;
&lt;p&gt;3.1且表小，3w行采集全部采完，真实distinct=10000（假设），预估distinct=d=10000&lt;/p&gt;
&lt;p&gt;3.2且表大，采样中有重复出现的值，也有出现一次值（因为某个重复数据只采到一条），即n=30000,n/N=0，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;n*d / (n - f1 + f1*n/N)=n*d / (n - f1)=30000*d/(30000-f1)&lt;/code&gt;，也就是采样中的distinct数越大，预估的distinct越大；采样只出现一次值数越大，预估的distinct越大&lt;/p&gt;
&lt;p&gt;总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;distinct预估跟采样中的distinct数、只出现一次值数直接相关&lt;/li&gt;
&lt;li&gt;如果只出现一次值数=0，那么采样越多，预估的distinct越大&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="#%e9%aa%8c%e8%af%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于默认采样数最大是3w行，也就是说这种采样算法只要超过3w，即表比较大的时候，预估distinct很可能偏小。注意这里的数据不能有太多唯一值。&lt;/p&gt;
&lt;p&gt;测试一张表不同采样数的差异：&lt;/p&gt;
&lt;p&gt;表有reltuples=8亿，relpages=2kw，size=175GB，真实的某字段distinct 1亿&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;target statistics&lt;/th&gt;
 &lt;th&gt;pages采样比例（1）&lt;/th&gt;
 &lt;th&gt;tuples采样比例（1）&lt;/th&gt;
 &lt;th&gt;n_distinct&lt;/th&gt;
 &lt;th&gt;执行时间&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;50&lt;/td&gt;
 &lt;td&gt;0.00075&lt;/td&gt;
 &lt;td&gt;0.00001875&lt;/td&gt;
 &lt;td&gt;6w&lt;/td&gt;
 &lt;td&gt;2秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;100&lt;/td&gt;
 &lt;td&gt;0.0015&lt;/td&gt;
 &lt;td&gt;0.0000375&lt;/td&gt;
 &lt;td&gt;11w&lt;/td&gt;
 &lt;td&gt;5秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1000&lt;/td&gt;
 &lt;td&gt;0.015&lt;/td&gt;
 &lt;td&gt;0.000375&lt;/td&gt;
 &lt;td&gt;103w&lt;/td&gt;
 &lt;td&gt;58秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3000&lt;/td&gt;
 &lt;td&gt;0.045&lt;/td&gt;
 &lt;td&gt;0.001125&lt;/td&gt;
 &lt;td&gt;268w&lt;/td&gt;
 &lt;td&gt;3分01秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10000&lt;/td&gt;
 &lt;td&gt;0.15&lt;/td&gt;
 &lt;td&gt;0.00375&lt;/td&gt;
 &lt;td&gt;675w&lt;/td&gt;
 &lt;td&gt;7分21秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（target statistics 最大值10000）&lt;/p&gt;
&lt;p&gt;可以粗糙的总结：n_distinct和analyze的执行时间随采样数量成倍增长。&lt;/p&gt;
&lt;p&gt;n_distinct随采样数量增长，pages和tuples却一直都很准确。&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%a7%a3%e5%86%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于表特别大，可以考虑改造分区表或根据实际SQL进行优化&lt;/p&gt;
&lt;p&gt;还可以调整收集阈值，默认阈值&lt;code&gt;default_statistics_target=100&lt;/code&gt;，即3w个pages中的3w条数据。&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;set&lt;/span&gt; default_statistics_target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&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;&lt;span style="color:#66d9ef"&gt;analyze&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;长期方案：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; tab1 &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;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;STATISTICS&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3000&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;default_statistics_target&lt;/code&gt;参数&lt;/li&gt;
&lt;li&gt;收集阈值最大为10000&lt;/li&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-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;	 * Determine how many rows we need to sample, using the worst case from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * all analyzable columns. We use a lower bound of 100 rows to avoid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * possible overflow in Vitter&amp;#39;s algorithm. (Note: that will also be 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;	 * target in the corner case where there are no analyzable columns.)
&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;	targrows &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:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; attr_cnt; i&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;if&lt;/span&gt; (targrows &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; vacattrstats[i]&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;minrows)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			targrows &lt;span style="color:#f92672"&gt;=&lt;/span&gt; vacattrstats[i]&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;minrows;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (ind &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; ind &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; nindexes; ind&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;		AnlIndexData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;thisdata &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;indexdata[ind];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; thisdata&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;attr_cnt; i&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;if&lt;/span&gt; (targrows &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; thisdata&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;vacattrstats[i]&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;minrows)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				targrows &lt;span style="color:#f92672"&gt;=&lt;/span&gt; thisdata&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;vacattrstats[i]&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;minrows;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;analyze&lt;/code&gt;发现收集多了或者少了，可以看下&lt;code&gt;pg_statistic&lt;/code&gt;是不是有设置字段&lt;code&gt;stattarget&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; attrelid::regclass,attname,attstattarget &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_attribute &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; attrelid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;tab1&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; attstattarget &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&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;);&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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;对于大表，字段非唯一但distinct值比较高（符合真实场景），采样算法会低估distinct值，且跟采样比例正相关。默认的采样比例对于大表来说偏小，可以调大，但是最大也大不到哪去。&lt;/p&gt;</content:encoded></item><item><title>案例-添加索引性能下降和generic plan</title><link>https://lastdba.com/2025/09/13/%E6%A1%88%E4%BE%8B-%E6%B7%BB%E5%8A%A0%E7%B4%A2%E5%BC%95%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%92%8Cgeneric-plan/</link><pubDate>Sat, 13 Sep 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/09/13/%E6%A1%88%E4%BE%8B-%E6%B7%BB%E5%8A%A0%E7%B4%A2%E5%BC%95%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%92%8Cgeneric-plan/</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;前晚添加索引，第二天早上cpu打爆，sql容易定位，问题sql就1条。该sql跑了30多s，但是昨天跑3s左右，所以要看下前后执行计划变化。&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;前晚添加索引，第二天早上cpu打爆，sql容易定位，问题sql就1条。该sql跑了30多s，但是昨天跑3s左右，所以要看下前后执行计划变化。&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; Nested Loop (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;92&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2259694&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;265822&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&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; uk_lzl_task &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_task t (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;20007&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;99&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;195&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_by)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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; Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11337&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;14842&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;57&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; lzl_202501 cc_1 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3053&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;1467&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&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: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202501_task_no_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;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;1594&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: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::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; lzl_202502 cc_2 (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;67&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3066&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&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;1604&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&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: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; Bitmap &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202502_task_no_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;21&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;1605&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: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; lzl_202503_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202503 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1362&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;61&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;1637&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;57&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: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202504_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202504 cc_4 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;604&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;64&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;1795&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202505_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202505 cc_5 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;445&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;1450&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202506_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202506 cc_6 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;583&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;1675&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202507_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202507 cc_7 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;633&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;45&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;1973&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202508_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202508 cc_8 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;619&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;43&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;1720&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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; lzl_202509_task_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_202509 cc_9 (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;893&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;1521&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-07 09: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-03 12:56:44.973&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;created_date时间范围，找1年的数据，前晚变更加的索引是created_date。&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:#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;63&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;23740&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;82&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;191&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: ((cc.task_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::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; 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;23376&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;114435&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Subplans Removed: &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:#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_lzltab_202501_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202501 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1450&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;59&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;8958&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&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: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202502_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202502 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1822&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;73&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;7405&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&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: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202503_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202503 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1430&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;7917&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;57&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: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202504_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202504 cc_4 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2412&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;11041&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202505_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202505 cc_5 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2260&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;73&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;13381&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202506_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202506 cc_6 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3930&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;17832&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202507_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202507 cc_7 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3878&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;77&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;21786&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202508_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202508 cc_8 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;4736&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;72&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;22033&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202509_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202509 cc_9 (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;627&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;1893&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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; Hash (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;63&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;27&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&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; ai_outbound_call_task t (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;99&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;63&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;27&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&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: ((created_by)::text &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;3&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; idx_ai_call_task_c (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;99&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;27&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: ((created_by)::text &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;3&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;新的执行计划从task_no索引变成走created_date索引，nl变成hash join。cost从2259694减少到23740，减少100倍。但是，实际执行时间增加了10倍左右。&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%ae%9a%e4%bd%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从3个问题来带入分析定位：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;为什么优化人员建议了created_date索引？&lt;/li&gt;
&lt;li&gt;为什么走到了新的索引？&lt;/li&gt;
&lt;li&gt;为什么新的执行计划执行时间很长但预估rows很小？&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;为什么优化人员建议了created_date索引？
 &lt;div id="为什么优化人员建议了created_date索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%98%e5%8c%96%e4%ba%ba%e5%91%98%e5%bb%ba%e8%ae%ae%e4%ba%86created_date%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果直接把pg日志中参数回填到sql文本，执行计划其实是好的那一个，也就是跑3s的走task_no索引的plan。优化人员也这么跑了，发现还可以。但是生产环境却不是这个执行计划。&lt;/p&gt;
&lt;p&gt;即使强制不让走task_no索引，优化器选择全表扫描都不去走create date索引：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; Hash Cond: (((cc.task_no)::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 style="color:#f92672"&gt;=&lt;/span&gt; (t.task_no)::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; 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;2794425&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;58&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;22238757&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;57&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; lzltab_202501 cc_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;193060&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;05&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;1585238&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&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; lzltab_202502 cc_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;178567&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;54&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;1480969&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((created_date &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11: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; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&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; lzltab_202503 cc_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;191073&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;1583356&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这就很奇怪，自己怎么跑都走不到created_date烂索引，生产环境又是怎么走到created_date的？&lt;/p&gt;
&lt;p&gt;联想到有绑定变量，有可能会是generic plan。&lt;/p&gt;
&lt;p&gt;generic plan的特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当&lt;code&gt;force_custom_plan =auto&lt;/code&gt;时，对比generic plan和avg(前五次硬解析的执行计划的代价)，如果generic plan更小就用generic plan，后续不再进行硬解析；否则每次都硬解析（见源码&lt;code&gt;choose_custom_plan&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;generic plan长什么样子跟绑定变量本身是多少没有关系&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:#66d9ef"&gt;PREPARE&lt;/span&gt; sql1(&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;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;,text) &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;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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xxxxxxx...;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;367&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;220&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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;254&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;386&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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;343&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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;234&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;110&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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;233&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;570&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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;2025-01-08 11:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;2025-09-04 08:31:43&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;LIUZHILONG62&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;12016&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;Time: &lt;span style="color:#ae81ff"&gt;70678&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;344&lt;/span&gt; ms (&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;678&lt;/span&gt;) &lt;span style="color:#75715e"&gt;--第6次执行时间明显变长
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span 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; &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_statements&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx &lt;span style="color:#75715e"&gt;--pg14支持pg_prepared_statements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;generic_plans &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;custom_plans &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &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;p&gt;前5次硬解析用custom_plans跑出来都很快，第6次用到generic_plan，走的created_date，即为生产的故障计划，非常慢。&lt;/p&gt;
&lt;p&gt;所以优化建议里用created_date是有些问题，但是替换变量为具体值后explain出来的执行计划是对的，而生产环境业务用绑定变量跑，跑到了generic plan，故障就此出现。&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么新的执行计划执行时间很长但预估rows很小？
 &lt;div id="为什么新的执行计划执行时间很长但预估rows很小" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e6%96%b0%e7%9a%84%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e6%89%a7%e8%a1%8c%e6%97%b6%e9%97%b4%e5%be%88%e9%95%bf%e4%bd%86%e9%a2%84%e4%bc%b0rows%e5%be%88%e5%b0%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;故障执行计划有个问题，预估的cost太小，rows太少&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_lzltab_202501_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202501 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1450&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;59&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;8958&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&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: ((created_date &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:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (created_date &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$&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;这从业务逻辑上看这有点不正常，因为create_date条件已经跨了多个分区，created_date是分区键，那么where created&amp;gt;=xx &amp;lt;=yy一定是连续的，在子分区上的选择率应该始终为1，rows应是子分区行数，应该是几百万而不是几千。&lt;/p&gt;
&lt;p&gt;刚开始以为是统计信息的问题，但统计信息是比较准确的，202501的历史分区数据没有什么变动。&lt;/p&gt;
&lt;p&gt;既然是generic plan需要从generic plan预估代价入手翻源码。cost要难一点，看rows的预估逻辑要相对简单些，也容易定位。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;double&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;calc_rangesel&lt;/span&gt;(TypeCacheEntry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;typcache, VariableStatData &lt;span style="color:#f92672"&gt;*&lt;/span&gt;vardata,
&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; RangeType &lt;span style="color:#f92672"&gt;*&lt;/span&gt;constval, Oid operator)
&lt;/span&gt;&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* with any other operator, empty Op non-empty matches nothing */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			selec &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; empty_frac) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; hist_selec;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* all range operators are strict */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	selec &lt;span style="color:#f92672"&gt;*=&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; null_frac);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;range_select=(1-null率)*直方图选择率&lt;/code&gt;，range直方图选择率看range命中的直方图对应的选择率再加个命中的MCV即可。不过这个案例不用算这些。&lt;/p&gt;
&lt;p&gt;因为generic plan不看直方图：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * rangesel -- restriction selectivity for range operators
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;rangesel&lt;/span&gt;(PG_FUNCTION_ARGS)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	 * If we got a valid constant on one side of the operator, proceed 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;	 * estimate using statistics. Otherwise punt and return a default constant
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * estimate. Note that calc_rangesel need not handle
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * OID_RANGE_ELEM_CONTAINED_OP.
&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; (constrange)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		selec &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calc_rangesel&lt;/span&gt;(typcache, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;vardata, constrange, operator);
&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;		selec &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default_range_selectivity&lt;/span&gt;(operator);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;calc_rangesel&lt;/code&gt;就是上面那个有常量值传入的选择率计算，else就是默认选择率函数&lt;code&gt;default_range_selectivity&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; * Returns a default selectivity estimate for given operator, when we don&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; * have statistics or cannot use them for some reason.
&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;double&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;default_range_selectivity&lt;/span&gt;(Oid operator)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (operator)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;case&lt;/span&gt; OID_RANGE_CONTAINS_ELEM_OP:
&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; OID_RANGE_ELEM_CONTAINED_OP:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;			 * &amp;#34;range @&amp;gt; elem&amp;#34; is more or less identical to a scalar
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * inequality &amp;#34;A &amp;gt;= b AND A &amp;lt;= 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:#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; DEFAULT_RANGE_INEQ_SEL;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;range的默认选择率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;/* default selectivity estimate for range inequalities &amp;#34;A &amp;gt; b AND A &amp;lt; 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:#75715e"&gt;#define DEFAULT_RANGE_INEQ_SEL	0.005&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;返回生产环境计算rows&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; reltuples::bigint&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;005&lt;/span&gt; &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;lzltab_202501&amp;#39;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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 style="color:#f92672"&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8958&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;350&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这跟实际的rows估算值8958相等：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;idx_lzltab_202501_created_date &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzltab_202501 cc_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1450&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;59&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;8958&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;66&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所以新的执行计划估算不准确是因为generic plan使用了默认的选择率。&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%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;为什么要有generic plan以及软解析的问题
 &lt;div id="为什么要有generic-plan以及软解析的问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e8%a6%81%e6%9c%89generic-plan%e4%bb%a5%e5%8f%8a%e8%bd%af%e8%a7%a3%e6%9e%90%e7%9a%84%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;把generic plan看成是DEFAULT estimate plan还更容易理解一点&lt;/p&gt;
&lt;p&gt;为什么generic plan好像总是有问题？&lt;/p&gt;
&lt;p&gt;理出以下思维链：&lt;/p&gt;
&lt;p&gt;generic plan是为了减少硬解析，即使用软解析
如果不是每次执行都是硬解析，那么可以不传入具体参数直接使用执行计划
如果不传参直接用执行计划，那么需要提前生成执行计划&lt;/p&gt;
&lt;p&gt;提前生成执行计划的方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不传参执行计划（generic plan）&lt;/li&gt;
&lt;li&gt;用前几次传参生成的执行计划（pg没有这种东西）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果使用generic plan，有可能是不准确的，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1.数据倾斜（如某个mcv极高，如where a=1，但a=1非常多），这极度依赖传入参数本身是啥，但generic plan不传参，所以执行计划不可能准确&lt;/li&gt;
&lt;li&gt;2.数据均衡但无法准确计算选择率（如where a&amp;gt;$1 and a&amp;lt;$2），如果不知道range没人能计算出选择率，但generic plan不传参，所以执行计划不可能准确&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果前几次传参执行计划（pg没有这种东西），有可能也是不准确的，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据倾斜，前几次传参没有普遍性，前几次传参极大的影响了后续固定的执行计划是什么&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;generic plan预估不准的问题分类
 &lt;div id="generic-plan预估不准的问题分类" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#generic-plan%e9%a2%84%e4%bc%b0%e4%b8%8d%e5%87%86%e7%9a%84%e9%97%ae%e9%a2%98%e5%88%86%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为要5次对比，所以generic plan的问题可以分为2种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;前5次SQL的执行没有普遍性。跟前5次执行计划相关性大，依赖数据倾斜和前5次参数是否具有普遍性。&lt;/li&gt;
&lt;li&gt;generic plan本身有问题。generic plan因为数据倾斜或数据均衡但无法准确计算选择率，导致generic plan本身执行效率低下&lt;/li&gt;
&lt;/ol&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%bc%98%e5%8c%96%e6%96%b9%e6%a1%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;从这个案例看下来，generic plan问题在分区表上可能会出现，分区键是连续的，扫描所有分区建选择率应该为1，但generic plan为0.05，很可能导致走“全索引”扫描这种场景。&lt;/p&gt;
&lt;p&gt;所以在优化的时候需要考虑更多：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要建太多索引迷惑优化器&lt;/li&gt;
&lt;li&gt;排除generic plan的干扰。用&lt;code&gt;EXECUTE&lt;/code&gt;真实跑6次&lt;/li&gt;
&lt;li&gt;会话级别&lt;code&gt;set plan_cache_mode='force_generic_plan'&lt;/code&gt;; or &lt;code&gt;set plan_cache_mode='force_custom_plan';&lt;/code&gt;对比执行计划；或者在pg16+用explain (GENERIC_PLAN)对比执行计划&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--prepare/excute
&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; sql1(text) &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;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; LZL &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&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;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:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;zzz&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&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;EXPLAIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; sql1(&lt;span style="color:#e6db74"&gt;&amp;#39;zzz&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;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_statements &lt;span style="color:#75715e"&gt;--查看prepare语句信息，只能看当前会话
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--对比执行计划，设置会话参数后执行EXPLAIN EXECUTE
&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; plan_cache_mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;force_generic_plan&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;set&lt;/span&gt; plan_cache_mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;force_custom_plan&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;--直接查看genetic plan,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;explain&lt;/span&gt; (GENERIC_PLAN) xx &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&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>控制文件上的参数和主从参数不一致问题</title><link>https://lastdba.com/2025/08/25/%E6%8E%A7%E5%88%B6%E6%96%87%E4%BB%B6%E4%B8%8A%E7%9A%84%E5%8F%82%E6%95%B0%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%8F%82%E6%95%B0%E4%B8%8D%E4%B8%80%E8%87%B4%E9%97%AE%E9%A2%98/</link><pubDate>Mon, 25 Aug 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/08/25/%E6%8E%A7%E5%88%B6%E6%96%87%E4%BB%B6%E4%B8%8A%E7%9A%84%E5%8F%82%E6%95%B0%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%8F%82%E6%95%B0%E4%B8%8D%E4%B8%80%E8%87%B4%E9%97%AE%E9%A2%98/</guid><description>&lt;h3 class="relative group"&gt;PARAMETER_CHANGE和控制文件上的数据库参数
 &lt;div id="parameter_change和控制文件上的数据库参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#parameter_change%e5%92%8c%e6%8e%a7%e5%88%b6%e6%96%87%e4%bb%b6%e4%b8%8a%e7%9a%84%e6%95%b0%e6%8d%ae%e5%ba%93%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg有些参数会影响从库的运行，而这些参数不仅在参数文件中，也写到controlfile，只要参数改变就会写入wal并更新控制文件。
从库会通过&lt;code&gt;PARAMETER_CHANGE&lt;/code&gt; wal record进行redo，写入到从库的controlfile中。
&lt;code&gt;PARAMETER_CHANGE&lt;/code&gt; wal record：&lt;/p&gt;</description><content:encoded>
&lt;h3 class="relative group"&gt;PARAMETER_CHANGE和控制文件上的数据库参数
 &lt;div id="parameter_change和控制文件上的数据库参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#parameter_change%e5%92%8c%e6%8e%a7%e5%88%b6%e6%96%87%e4%bb%b6%e4%b8%8a%e7%9a%84%e6%95%b0%e6%8d%ae%e5%ba%93%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg有些参数会影响从库的运行，而这些参数不仅在参数文件中，也写到controlfile，只要参数改变就会写入wal并更新控制文件。
从库会通过&lt;code&gt;PARAMETER_CHANGE&lt;/code&gt; wal record进行redo，写入到从库的controlfile中。
&lt;code&gt;PARAMETER_CHANGE&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: XLOG len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 54/ 54, tx: 0, lsn: 27F/800001C0, prev 27F/80000148, desc: PARAMETER_CHANGE max_connections&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt; max_worker_processes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; max_wal_senders&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; max_prepared_xacts&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max_locks_per_xact&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt; wal_level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;logical wal_log_hints&lt;span style="color:#f92672"&gt;=&lt;/span&gt;off track_commit_timestamp&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;code&gt;XLOG_PARAMETER_CHANGE&lt;/code&gt;记录了这8种参数，控制文件也可以直接看，：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_controldata |grep setting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_level setting: logical
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_log_hints setting: on
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_connections setting: &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;max_worker_processes setting: &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;max_wal_senders setting: &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;max_prepared_xacts setting: &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;max_locks_per_xact setting: &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;track_commit_timestamp setting: on&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;。
startup进程通过&lt;code&gt;CheckRequiredParameterValues&lt;/code&gt;函数检查6个参数是否满足条件。其中1个参数&lt;code&gt;wal_level&lt;/code&gt;&amp;gt;=&lt;code&gt;replica&lt;/code&gt;，另外5个参数&lt;code&gt;max_connections&lt;/code&gt;,&lt;code&gt;max_worker_processes&lt;/code&gt;,&lt;code&gt;max_wal_senders&lt;/code&gt;,&lt;code&gt;max_prepared_transactions&lt;/code&gt;,&lt;code&gt;max_locks_per_transaction&lt;/code&gt;会检查主从大小，从库小的话会pause recovery。直接将主库参数调大，从库直接挂掉，pg 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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FATAL,&lt;span style="color:#ae81ff"&gt;22023&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;hot standby is not possible because max_connections = 2000 is a lower setting than on the master server (its value was 3000)&amp;#34;&lt;/span&gt;,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;WAL redo at 27F/800001C0 for XLOG/PARAMETER_CHANGE: max_connections=3000 max_worker_processes=20 max_wal_senders=10 max_prepared_xacts=0 max_locks_per_xact=1024 wal_level=logical wal_log_hints=off track_commit_timestamp=on&amp;#34;&lt;/span&gt;,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;startup&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;8个参数中的6个都可能严重影响从库的运行。另外2个参数&lt;code&gt;wal_log_hints&lt;/code&gt;,&lt;code&gt;track_commit_timestamp&lt;/code&gt;不会被startup进程立即检查。8个参数同步到控制文件都有其意义。&lt;/p&gt;

&lt;h3 class="relative group"&gt;wal_log_hint主从不一致
 &lt;div id="wal_log_hint主从不一致" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#wal_log_hint%e4%b8%bb%e4%bb%8e%e4%b8%8d%e4%b8%80%e8%87%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;wal_log_hints&lt;/code&gt;的变化会记录到wal日志中，虽然不会被startup进程检查，pg_rewind会检查：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;perform_rewind&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	 * Target cluster need to use checksums or hint bit wal-logging, this 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 from data corruption that could occur because of 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:#66d9ef"&gt;if&lt;/span&gt; (ControlFile_target.data_checksum_version &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; PG_DATA_CHECKSUM_VERSION &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;ControlFile_target.wal_log_hints)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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_fatal&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;target server needs to use either data checksums or &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;wal_log_hints = on&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为wal_log_hints是wal相关的，所以pg_rewind去检查从库的wal_log_hints参数有没有打开没有意义，应检查主库的wal_log_hints有没有打开，所以pg将wal_log_hints参数同步到从库的控制文件中了，非常合理。&lt;/p&gt;
&lt;p&gt;wal_log_hint主从不一致测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; t1;
&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:#66d9ef"&gt;update&lt;/span&gt; t1 &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;eee&amp;#39;&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;checkpoint&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--忽略该online checkpoint wal 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;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; t1; &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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_waldump &lt;span style="color:#ae81ff"&gt;000000020000027&lt;/span&gt;F0000000A&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;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;-- observing 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;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;t1&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;on，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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点1：
&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;: 85/ 208, tx: 11140182, lsn: 27F/5000CC38, prev 27F/5000CBC0, desc: HOT_UPDATE off &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;11140182&lt;/span&gt; flags 0x10 ; new off &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Transaction len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 46/ 46, tx: 11140182, lsn: 27F/5000CD08, prev 27F/5000CC38, desc: COMMIT 2025-07-21 18:28:13.292397 CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/5000CD38, prev 27F/5000CD08, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140182&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点2：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: XLOG len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 51/ 171, tx: 0, lsn: 27F/58000110, prev 27F/580000D8, desc: FPI_FOR_HINT , blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/580001C0, prev 27F/58000110, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140182&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;off,off:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--观察点1：
&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;: 85/ 225, tx: 11140183, lsn: 27F/580003C8, prev 27F/58000390, desc: HOT_UPDATE off &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt; flags 0x10 ; new off &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Transaction len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 46/ 46, tx: 11140183, lsn: 27F/580004B0, prev 27F/580003C8, desc: COMMIT 2025-07-21 18:33:18.192146 CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/580004E0, prev 27F/580004B0, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140184&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140184&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/58000518, prev 27F/580004E0, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140184&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140183&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140184&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点2：&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;on，off:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--观察点1：
&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;: 85/ 274, tx: 11140186, lsn: 27F/58000C18, prev 27F/58000BA0, desc: HOT_UPDATE off &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; flags 0x10 ; new off &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Transaction len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 46/ 46, tx: 11140186, lsn: 27F/58000D30, prev 27F/58000C18, desc: COMMIT 2025-07-21 18:40:17.638691 CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/58000D60, prev 27F/58000D30, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/58000D98, prev 27F/58000D60, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点2：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: XLOG len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 51/ 236, tx: 0, lsn: 27F/58000E48, prev 27F/58000DD0, desc: FPI_FOR_HINT , blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/58000F38, prev 27F/58000E48, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;off，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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点1：
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/58001108, prev 27F/58001090, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140187&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;: 85/ 289, tx: 11140187, lsn: 27F/58001140, prev 27F/58001108, desc: HOT_UPDATE off &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; flags 0x10 ; new off &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/7472552/7472597 blk 0 FPW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Transaction len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 46/ 46, tx: 11140187, lsn: 27F/58001268, prev 27F/58001140, desc: COMMIT 2025-07-21 18:44:08.550109 CST
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 54/ 54, tx: 0, lsn: 27F/58001298, prev 27F/58001268, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140188&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140186&lt;/span&gt; oldestRunningXid 11140187; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xacts: &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 27F/580012D0, prev 27F/58001298, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;11140188&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;11140187&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;11140188&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--观察点2：&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;FPI_FOR_HINT在hintbit回写时产生，查询语句可产生FPI_FOR_HINT&lt;/li&gt;
&lt;li&gt;无论从on or off，主为on的时候，FPI_FOR_HINT就会生产&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;附加知识：what is XLOG_RUNNING_XACTS
 &lt;div id="附加知识what-is-xlog_running_xacts" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%99%84%e5%8a%a0%e7%9f%a5%e8%af%86what-is-xlog_running_xacts" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;XLOG_RUNNING_XACTS是RM_STANDBY_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;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * XLOG message types
&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 XLOG_STANDBY_LOCK			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 XLOG_RUNNING_XACTS			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_INVALIDATIONS			0x20&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;XLOG_STANDBY_LOCK&lt;/code&gt;：记录 AccessExclusiveLock 的获取和释放，用于 Standby 节点识别锁状态。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;XLOG_RUNNING_XACTS&lt;/code&gt;： running-xacts snapshots用于构建快照，确保事务一致性&lt;/p&gt;
&lt;p&gt;&lt;code&gt;XLOG_INVALIDATIONS&lt;/code&gt;：INVALIDATIONS消息，用于同时效元数据信息给local 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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; standbydefs.h
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;	 Frontend exposed definitions &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; hot standby mode.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RM_STANDBY_ID&lt;/code&gt;是专门为hot standby只读从库定义的rmgr。对于本地实例恢复、逻辑解析这些需要用到wal的场景，``RM_STANDBY_ID`本质上对他们没有意义。&lt;/p&gt;
&lt;p&gt;测试事务提交观察wal record：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;command&lt;/th&gt;
 &lt;th&gt;wal record&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;begin;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;select * from txid_current(); &amp;ndash;11140191&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;commit;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;rmgr: Transaction&lt;/strong&gt; len (rec/tot): 46/ 46, &lt;strong&gt;tx: 11140191&lt;/strong&gt;, lsn: 27F/80000538, prev 27F/80000500, desc: COMMIT 2025-07-23 11:16:10.872724 CST&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;rmgr: Standby&lt;/strong&gt; len (rec/tot): 50/ 50, tx: 0, lsn: 27F/80000568, prev 27F/80000538, desc: RUNNING_XACTS &lt;strong&gt;nextXid 11140192 latestCompletedXid 11140191&lt;/strong&gt; oldestRunningXid 11140192&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;事务id 本身commit or abort还是rmgr: Transaction在同步，快照通过rmgr: Standby RUNNING_XACTS 同步。&lt;/p&gt;

&lt;h3 class="relative group"&gt;track_commit_timestamp主从不一致
 &lt;div id="track_commit_timestamp主从不一致" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#track_commit_timestamp%e4%b8%bb%e4%bb%8e%e4%b8%8d%e4%b8%80%e8%87%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;track_commit_timestamp&lt;/code&gt;，startup进程会在接受到相应wal后将从库的commit ts功能激活，主要是为从库查看xid提交时间用:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Activate or deactivate CommitTs&amp;#39; upon reception of a XLOG_PARAMETER_CHANGE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * XLog record during recovery.
&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;CommitTsParameterChange&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; newvalue, &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; oldvalue)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 commit_ts module is disabled in this server and we get word from
&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 primary server that it is enabled there, activate it so that we 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;	 * replay future WAL records involving it; also mark it as active on
&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_control. If the old value was already set, we already did this, so
&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 do anything.
&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 module is disabled in the primary, disable it here too, unless
&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 module is enabled locally.
&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 this only runs in the recovery process, so an unlocked read 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;	 * fine.
&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; (newvalue)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;commitTsShared&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;commitTsActive)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ActivateCommitTs&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (commitTsShared&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;commitTsActive)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;DeactivateCommitTs&lt;/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;track_commit_timestamp&lt;/code&gt;主从不一致测试，测试步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;初始状态，主=on，从=on 。均能使用committed_xact等函数&lt;/li&gt;
&lt;li&gt;主=off（重启主库），从库=on（不动）。均不能使用committed_xact等函数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;主库修改并重启后，从库复制依然正常，committed_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-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;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_last_committed_xact();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;: could &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;commit&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;timestamp&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;HINT: Make sure the configuration &lt;span style="color:#66d9ef"&gt;parameter&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;track_commit_timestamp&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; server.
&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;: error_commit_ts_disabled, commit_ts.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;385&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;show&lt;/span&gt; track_commit_timestamp
&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; track_commit_timestamp 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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:#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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;198&lt;/span&gt; ms
&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:#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 style="color:#f92672"&gt;##&lt;/span&gt; pg_controldata &lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep track_commit_timestamp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;track_commit_timestamp setting: &lt;span style="color:#66d9ef"&gt;off&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+ pause recovery
 &lt;div id="pg14-pause-recovery" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-pause-recovery" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg14对主库参数修改导致从库宕机做了提升。当参数不满足条件时，只读从库直接宕掉改成只读从库不宕只停复制，代码见&lt;code&gt;RecoveryRequiresIntParameter&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Pause recovery on a hot standby server if the primary changes its parameters in a way that prevents replay on the standby (Peter Eisentraut)&lt;/p&gt;
&lt;p&gt;Previously the standby would shut down immediately&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;测试pg14修改参数导致从库复制中断：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;46&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;31&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;337&lt;/span&gt; CST,,,&lt;span style="color:#ae81ff"&gt;141823&lt;/span&gt;,,&lt;span style="color:#ae81ff"&gt;6880&lt;/span&gt;ca5f.&lt;span style="color:#ae81ff"&gt;229&lt;/span&gt;ff,&lt;span style="color:#ae81ff"&gt;14&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;07&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;41&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; CST,&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;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;recovery has paused&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;If recovery is unpaused, the server will shut down.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;You can then restart the server after making the necessary configuration changes.&amp;#34;&lt;/span&gt;,,,&lt;span style="color:#e6db74"&gt;&amp;#34;WAL redo at 281/78324BE8 for XLOG/PARAMETER_CHANGE: max_connections=2000 max_worker_processes=20 max_wal_senders=10 max_prepared_xacts=0 max_locks_per_xact=1024 wal_level=logical wal_log_hints=on track_commit_timestamp=on&amp;#34;&lt;/span&gt;,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;startup&amp;#34;&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;em&gt;只能&lt;/em&gt;修改从库参数并重启（log的提示也很明显了）。&lt;/p&gt;

&lt;h3 class="relative group"&gt;小结8个参数
 &lt;div id="小结8个参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%938%e4%b8%aa%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;8个参数在主库被修改并重启后，均会更新本地控制文件，如果参数有变会将改变后的参数写入wal中同步给下游，下游redo这个parameter change wal record，即更新本地的控制文件，从库根据一定条件来判断主从或者其他功能是否可用。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;写到控制文件中的8个参数&lt;/th&gt;
 &lt;th&gt;check&lt;/th&gt;
 &lt;th&gt;if not,standby(pg13-)&lt;/th&gt;
 &lt;th&gt;if not,standby(pg14+)&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;wal_level&lt;/td&gt;
 &lt;td&gt;!=minimal&lt;/td&gt;
 &lt;td&gt;无法同步，原理性问题&lt;/td&gt;
 &lt;td&gt;无法同步，原理性问题&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_connections&lt;/td&gt;
 &lt;td&gt;主&amp;lt;=从&lt;/td&gt;
 &lt;td&gt;hot standby宕机&lt;/td&gt;
 &lt;td&gt;hot standby停止同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_worker_processes&lt;/td&gt;
 &lt;td&gt;主&amp;lt;=从&lt;/td&gt;
 &lt;td&gt;hot standby宕机&lt;/td&gt;
 &lt;td&gt;hot standby停止同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_wal_senders&lt;/td&gt;
 &lt;td&gt;主&amp;lt;=从&lt;/td&gt;
 &lt;td&gt;hot standby宕机&lt;/td&gt;
 &lt;td&gt;hot standby停止同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_prepared_transactions&lt;/td&gt;
 &lt;td&gt;主&amp;lt;=从&lt;/td&gt;
 &lt;td&gt;hot standby宕机&lt;/td&gt;
 &lt;td&gt;hot standby停止同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;max_locks_per_transaction&lt;/td&gt;
 &lt;td&gt;主&amp;lt;=从&lt;/td&gt;
 &lt;td&gt;hot standby宕机&lt;/td&gt;
 &lt;td&gt;hot standby停止同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;wal_log_hints&lt;/td&gt;
 &lt;td&gt;pg_rewind前置条件（either data checksums or wal_log_hints = on）&lt;/td&gt;
 &lt;td&gt;不影响standby同步&lt;/td&gt;
 &lt;td&gt;不影响standby同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;track_commit_timestamp&lt;/td&gt;
 &lt;td&gt;打开/关闭从库的commit_ts功能&lt;/td&gt;
 &lt;td&gt;不影响standby同步&lt;/td&gt;
 &lt;td&gt;不影响standby同步&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&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>案例-授权和walsender跑不动</title><link>https://lastdba.com/2025/06/26/%E6%A1%88%E4%BE%8B-%E6%8E%88%E6%9D%83%E5%92%8Cwalsender%E8%B7%91%E4%B8%8D%E5%8A%A8/</link><pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/06/26/%E6%A1%88%E4%BE%8B-%E6%8E%88%E6%9D%83%E5%92%8Cwalsender%E8%B7%91%E4%B8%8D%E5%8A%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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;walsender LSN未推进，堆栈显示堵在pathman的&lt;code&gt;invalidate_psin_entries_using_relid&lt;/code&gt;，relid改变，walsender cpu打满。&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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;walsender LSN未推进，堆栈显示堵在pathman的&lt;code&gt;invalidate_psin_entries_using_relid&lt;/code&gt;，relid改变，walsender cpu打满。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;pstack &lt;span style="color:#ae81ff"&gt;121327&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; hash_seq_search (status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;status&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;x7fffaadf8330) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; dynahash.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1441&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;x00002ba3b40ec728 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; invalidate_psin_entries_using_relid (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;42319501&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;251&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;x00002ba3b40ecb3d &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; forget_status_of_relation (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;42319501&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;232&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00002ba3b40fcc96 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pathman_relcache_hook (arg&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;, relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;42319501&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;hooks.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;934&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;x000000000087168a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; LocalExecuteInvalidationMessage (msg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x3a391c8) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; inval.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;595&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000071d50e &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ReorderBufferExecuteInvalidations (rb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1b63ff8, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1be5f58, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1be5f58) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; reorderbuffer.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2238&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; ReorderBufferCommit (rb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1b63ff8, xid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xid&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;4285897514&lt;/span&gt;, commit_lsn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;405674661986920&lt;/span&gt;, end_lsn&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;, commit_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;commit_time&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;799377897828299&lt;/span&gt;, origin_id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;origin_id&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;, origin_lsn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;origin_lsn&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;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; reorderbuffer.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1819&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000712d18 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; DecodeCommit (xid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4285897514&lt;/span&gt;, parsed&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x7fffaadf8630, buf&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x7fffaadf87f0, ctx&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a359e8) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; decode.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;637&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; DecodeXactOp (ctx&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a359e8, buf&lt;span style="color:#f92672"&gt;=&lt;/span&gt;buf&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;x7fffaadf87f0) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; decode.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;245&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;x00000000007130b2 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; LogicalDecodingProcessRecord (ctx&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a359e8, record&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a35c80) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; decode.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;114&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;x0000000000733662 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; XLogSendLogical () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; walsender.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2885&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;x0000000000735942 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; WalSndLoop (send_data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;send_data&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;x733620 &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;XLogSendLogical&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; walsender.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2287&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;x0000000000736692 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; StartLogicalReplication (cmd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1846c68) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; walsender.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1213&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; exec_replication_command (cmd_string&lt;span style="color:#f92672"&gt;=&lt;/span&gt;cmd_string&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;x181a288 &lt;span style="color:#e6db74"&gt;&amp;#34;START_REPLICATION SLOT \&amp;#34;&lt;/span&gt;lzl_logical_rep&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; LOGICAL 170F5/7C3EAE78 (\&amp;#34;&lt;/span&gt;proto_version&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#39;1&amp;#39;, \&amp;#34;&lt;/span&gt;publication_names&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#39;lzl_logical_rep&amp;#39;)&amp;#34;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; walsender.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1640&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;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000774e91 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; PostgresMain (argc&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;, 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;x1866478, dbname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x18662b8 &lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;, username&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; postgres.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4325&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;15&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000485989 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; BackendRun (port&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;, port&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; postmaster.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4526&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;16&lt;/span&gt; BackendStartup (port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x18635b0) &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;4210&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;17&lt;/span&gt; ServerLoop () &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;1739&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;18&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000000000702f08 &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;x1814da0) &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;1412&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;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000048660a &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;x1814da0) &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;span style="display: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;relid改变
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pstack &lt;span style="color:#ae81ff"&gt;121327&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; hash_seq_search (status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;status&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;x7fffaadf8330) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; dynahash.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1441&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;x00002ba3b40ec728 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; invalidate_psin_entries_using_relid (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;26560221&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;251&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;x00002ba3b40ecb3d &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; forget_status_of_relation (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;26560221&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;232&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00002ba3b40fcc96 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pathman_relcache_hook (arg&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;, relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;26560221&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;hooks.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;934&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;x000000000087168a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; LocalExecuteInvalidationMessage (msg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x39f1f68) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; inval.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;595&lt;/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;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%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;relid改变说明walsender还在跑还没有死。LSN没有改变，可以分析LSN的位置，看看这个事务在做什么。&lt;/p&gt;
&lt;p&gt;当时的信息还在的话，可以通过slot视图查restart LSN反查wal的位置。如果当时的信息不在，可以通过stack中的LSN来找到wal日志是哪个。&lt;/p&gt;
&lt;p&gt;pg_waldump查看wal日志信息，过滤xid&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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: Heap len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 961/ 961, tx: 4285897514, lsn: 170F5/7DFE3470, prev 170F5/7DFE3430, desc: UPDATE+INIT off &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; xmax &lt;span style="color:#ae81ff"&gt;4285897514&lt;/span&gt; flags 0x00 ; new off &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xmax 0, blkref &lt;span style="color:#75715e"&gt;#0: rel 1663/17662/1259 blk 8443, blkref #1: rel 1663/17662/1259 blk 7327&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;rmgr: Transaction len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 1778325/1778325, tx: 4285897514, lsn: 170F5/7E1F4268, prev 170F5/7E1F4220, desc: COMMIT 2025-05-01 09:24:57.828299 CST; inval msgs: catcache &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; catcache &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; catcache &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813261&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813255&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;51030741&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813252&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;50737247&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813246&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813243&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813237&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;50737241&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813234&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813224&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;49379811&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813216&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;48813210&lt;/span&gt; relcache &lt;span style="color:#ae81ff"&gt;45452775&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;rel 1663/17662/1259的record有18万条，最后一条record是inval msgs，catcache有7万，relcache 3万。&lt;/p&gt;
&lt;p&gt;rel 1663/17662/1259是pg_class，通过xmin去查pg_class可以找到对应的表和xid提交时间：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; xmin,xmax,pg_xact_commit_timestamp(xmin),relname &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; xmin&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;4285897514&amp;#39;&lt;/span&gt;::xid &lt;span style="color:#66d9ef"&gt;order&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; relname &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; xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xmax &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_xact_commit_timestamp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;4285897514&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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828299&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; v$session
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4285897514&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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828299&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; tmp_20230801_id_seq
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4285897514&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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828299&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; tmp_20230801
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4285897514&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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828299&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; test_param
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4285897514&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;2025&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828299&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; test_20240105
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#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; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; xmin&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;4285897514&amp;#39;&lt;/span&gt;::xid ;
&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;18523&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#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; pg_class ;
&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;139138&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过时间去查pglog日志：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2025-05-01 09:24:59.837 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,61418,&lt;span style="color:#e6db74"&gt;&amp;#34;[local]&amp;#34;&lt;/span&gt;,6812cd65.efea,3,&lt;span style="color:#e6db74"&gt;&amp;#34;DO&amp;#34;&lt;/span&gt;,2025-05-01 09:24:53 CST,549/0,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;duration: 6036.275 ms statement: 
&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; EXECUTE &amp;#39;GRANT SELECT ON ALL TABLES IN SCHEMA public TO r_lzldbdata_qry&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;...
&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; &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;psql&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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;基本可以定位是这个授权引起，因为授权会更新pgclass中的relacl，至少更新了1.8w个relation的权限，pgclass更新会触发invalidation消息，大量的invalidation消息在walsender进程中处理缓慢。&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%a4%8d%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;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;pg_recvlogical &lt;span style="color:#f92672"&gt;-&lt;/span&gt;h &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 style="color:#f92672"&gt;-&lt;/span&gt;p &lt;span style="color:#ae81ff"&gt;7997&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#f92672"&gt;-&lt;/span&gt;U repuser &lt;span style="color:#75715e"&gt;--slot=logical_test --start -f recv.sql &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;DO&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;FOR&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;20000&lt;/span&gt; LOOP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;CREATE TABLE IF NOT EXISTS table_%s ( 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; col1 varchar(10)
&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; lpad(i::text, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&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;END&lt;/span&gt; LOOP;
&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:#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:#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; &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; tables &lt;span style="color:#66d9ef"&gt;in&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;to&lt;/span&gt; r_lzldb_qry;&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;postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzlhost:&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pstack &lt;span style="color:#ae81ff"&gt;172862&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; hash_seq_search (status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;status&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;x7ffd664be280) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; dynahash.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1444&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;x00002ad31235e728 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; invalidate_psin_entries_using_relid (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;1002857&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;251&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;x00002ad31235eb3d &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; forget_status_of_relation (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;1002857&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;232&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00002ad31236ec96 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pathman_relcache_hook (arg&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;, relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1002857&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;hooks.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;934&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;x000000000087168a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; LocalExecuteInvalidationMessage (msg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2ad3c3f61a88) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; inval.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;595&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000071d50e &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ReorderBufferExecuteInvalidations (rb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x17e5698, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x180d698, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x180d698) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; reorderbuffer.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2238&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;lzlhost:&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pstack &lt;span style="color:#ae81ff"&gt;172862&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;x0000000000891d0c &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; hash_seq_search (status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;status&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;x7ffd664be280) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; dynahash.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1441&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;x00002ad31235e728 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; invalidate_psin_entries_using_relid (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;1011110&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;251&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;x00002ad31235eb3d &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; forget_status_of_relation (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;1011110&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;relation_info.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;232&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00002ad31236ec96 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pathman_relcache_hook (arg&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;, relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1011110&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; src&lt;span style="color:#f92672"&gt;/&lt;/span&gt;hooks.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;934&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;--relid在动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--cpu打满:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps &lt;span style="color:#f92672"&gt;-&lt;/span&gt;eo pid,&lt;span style="color:#f92672"&gt;%&lt;/span&gt;cpu,&lt;span style="color:#f92672"&gt;%&lt;/span&gt;mem&lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep &lt;span style="color:#ae81ff"&gt;172862&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;172862&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;99&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;3&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:#75715e"&gt;--运行2h左右追平&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;without pathman加速walsender解析
 &lt;div id="without-pathman加速walsender解析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#without-pathman%e5%8a%a0%e9%80%9fwalsender%e8%a7%a3%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为库里面是没有用pathman分区表的，但有pathman extension，所以尝试绕过pathman hook以加速walsender解析过程。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;drop&lt;/span&gt; extension pg_pathman;
&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;update&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; tables &lt;span style="color:#66d9ef"&gt;in&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;to&lt;/span&gt; r_lzldb_upd;
&lt;/span&gt;&lt;/span&gt;&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;lzlhost&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;grant&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pstack &lt;span style="color:#ae81ff"&gt;133460&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; hash_seq_search (status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;status&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;x7ffe292d5c90) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; dynahash.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1418&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;x000000000087f228 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; RelfilenodeMapInvalidateCallback (arg&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;, relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1034036&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; relfilenodemap.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;64&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;x000000000087168a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; LocalExecuteInvalidationMessage (msg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2b9699795768) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; inval.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;595&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000071d50e &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ReorderBufferExecuteInvalidations (rb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x195a358, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a6ff38, txn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1a6ff38) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; reorderbuffer.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2238&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; ReorderBufferCommit (rb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x195a358, xid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xid&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;328684387&lt;/span&gt;, commit_lsn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8016890875224&lt;/span&gt;, end_lsn&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;, commit_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;commit_time&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;799851538975691&lt;/span&gt;, origin_id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;origin_id&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;, origin_lsn&lt;span style="color:#f92672"&gt;=&lt;/span&gt;origin_lsn&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;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; reorderbuffer.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1819&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#ae81ff"&gt;20&lt;/span&gt;s以内完成&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;没有注释&lt;code&gt;shared_preload_libraries&lt;/code&gt;中的&lt;code&gt;pg_pathman&lt;/code&gt;，同样有很好的效果，walsender从2小时缩短到20s。&lt;/p&gt;
&lt;p&gt;这里感觉挺奇怪，没有注释&lt;code&gt;shared_preload_libraries&lt;/code&gt;，hook应该还是要走的。分析源码发现，之所以有效果是因为hook的第一步就有pathman config表的判断，不会再走pathman中的invalidate逻辑了，所以很快可以执行完成：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Invalidate PartRelationInfo cache entry if 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;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;pathman_relcache_hook&lt;/span&gt;(Datum arg, Oid relid)
&lt;/span&gt;&lt;/span&gt;&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 pathman_config_relid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* See cook_partitioning_expression() */&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;pathman_hooks_enabled)
&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:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;IsPathmanReady&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Invalidation event for PATHMAN_CONFIG table (probably DROP EXTENSION).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Digging catalogs here is expensive and probably illegal, so we take
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * cached relid. It is possible that we don&amp;#39;t know it atm (e.g. pathman
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * was disabled). However, in this case caches must have been cleaned
&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 disable, and there is no DROP-specific additional actions.
&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;	pathman_config_relid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_pathman_config_relid&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;if&lt;/span&gt; (relid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; pathman_config_relid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;delay_pathman_shutdown&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* Invalidation event for some user 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;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (relid &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; FirstNormalObjectId)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Invalidate PartBoundInfo entry if needed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;forget_bounds_of_rel&lt;/span&gt;(relid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Invalidate PartStatusInfo entry if needed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;forget_status_of_relation&lt;/span&gt;(relid);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Invalidate PartParentInfo entry if needed */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;forget_parent_of_partition&lt;/span&gt;(relid);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;get_pathman_config_relid&lt;/code&gt;获取了pathman_config表，&lt;code&gt;drop extension pg_pathman&lt;/code&gt;把db中pathman_config表删掉了，所以源码就不会走forget那一堆逻辑。&lt;/p&gt;
&lt;p&gt;也有其他办法可以加速walsender解析，比如将&lt;code&gt;pg_pathman.enable=off&lt;/code&gt;，会走&lt;code&gt;if (!IsPathmanReady())&lt;/code&gt;直接&lt;code&gt;return&lt;/code&gt;。或者最直接的注释&lt;code&gt;shared_preload_libraries&lt;/code&gt;中的&lt;code&gt;pg_pathman&lt;/code&gt;并重启实例（这是实例级不是db级）。&lt;/p&gt;

&lt;h2 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%e7%9a%84%e6%8f%90%e5%8d%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg14.0 release note:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Allow logical decoding to more efficiently process cache invalidation messages (Dilip Kumar) This allows logical decoding to work efficiently in presence of a large amount of DDL.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/release/14.0/" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/release/14.0/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;patch:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=d7eb52d71" target="_blank" rel="noreferrer"&gt;https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=d7eb52d71&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pg14&lt;code&gt;ReorderBufferAddInvalidations&lt;/code&gt;的注释：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;We require to record it in form of the change so that we can execute only the required invalidations instead of executing all the invalidations on each CommandId increment.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;对比pg14和pg13，&lt;code&gt;ReorderBufferCommit&lt;/code&gt;逻辑大改&lt;/p&gt;
&lt;p&gt;13中处理事务的逻辑直接放在commit函数里&lt;code&gt;ReorderBufferCommit&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;case&lt;/span&gt; REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
&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;(change&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.command_id &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; InvalidCommandId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (command_id &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; change&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.command_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;						command_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; change&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.command_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 style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;snapshot_now&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;copied)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 use the global one anymore */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							snapshot_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReorderBufferCopySnap&lt;/span&gt;(rb, snapshot_now,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;																 txn, command_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;						snapshot_now&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;curcid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; command_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 style="color:#a6e22e"&gt;TeardownHistoricSnapshot&lt;/span&gt;(false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#a6e22e"&gt;SetupHistoricSnapshot&lt;/span&gt;(snapshot_now, txn&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;tuplecid_hash);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;						 * Every time the CommandId is incremented, we 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;						 * see new catalog contents, so execute all
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;						 * invalidations.
&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;ReorderBufferExecuteInvalidations&lt;/span&gt;(rb, txn);
&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;14中的主要逻辑是&lt;code&gt;ReorderBufferReplay&lt;/code&gt;-&amp;gt;&lt;code&gt;ReorderBufferProcessTXN&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;ReorderBufferProcessTXN&lt;/code&gt;中新增&lt;code&gt;case REORDER_BUFFER_CHANGE_INVALIDATION&lt;/code&gt;判断以执行&lt;code&gt;ReorderBufferExecuteInvalidations&lt;/code&gt;执行reorderbuffer中的invalidate&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;case&lt;/span&gt; REORDER_BUFFER_CHANGE_INVALIDATION:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#75715e"&gt;/* Execute the invalidation messages locally */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;ReorderBufferExecuteInvalidations&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;													 change&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.inval.ninvalidations,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;													 change&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data.inval.invalidations);
&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;&lt;code&gt;ReorderBufferExecuteInvalidations&lt;/code&gt;之后的逻辑都差不多，没有多大变动。13对比14的&lt;code&gt;ReorderBufferCommit&lt;/code&gt;主要差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReorderBufferCommit&lt;/code&gt;不再是主要process txn的函数，调用栈更深&lt;/li&gt;
&lt;li&gt;新增&lt;code&gt;case REORDER_BUFFER_CHANGE_INVALIDATION&lt;/code&gt;判断，与&lt;code&gt;REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID&lt;/code&gt;标识区分，单独处理invalidation&lt;/li&gt;
&lt;li&gt;移除以每个command_id处理invalidation的逻辑&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%a0%b9%e5%9b%a0%e5%92%8c%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;walsender卡住的根因是有批量授权任务，导致pg_class多个元组更新，触发大量invalidation消息。&lt;code&gt;GRANT privs ON ALL TABLES IN SCHEMA public TO role1&lt;/code&gt; 这样的授权语句在pg中是1个事务多个command处理的，而pg13 逻辑复制处理invalidation message时，会通过每个command去处理一次reorder buffer invalidate，并处理各个hook的inval hash表。在这个场景中，pathman hook在处理inval hash表较慢，从而导致复制延迟。&lt;/p&gt;
&lt;p&gt;pathman处理较慢的触发条件（且）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg13-&lt;/li&gt;
&lt;li&gt;批量授权&lt;/li&gt;
&lt;li&gt;安装了pathman extension（无论是否使用）&lt;/li&gt;
&lt;li&gt;逻辑复制链路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即使将pathman干掉，也会在RelfilenodeMapInvalidateCallback等函数上花较多cpu。pg13目前测下来，有pathman对比没有pathman，处理时间是小时级和分钟级的差距。&lt;/p&gt;
&lt;p&gt;其他未测试但社区提及的场景（且）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg13-&lt;/li&gt;
&lt;li&gt;批量DDL/TRUNCATE/DCL/DROP PUBLICATION&lt;/li&gt;
&lt;li&gt;逻辑复制链路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;短期解决办法：如果没有用到pathman表的，可以drop extension或者不加载pathman so；重启链路&lt;/p&gt;
&lt;p&gt;长期解决办法：升级到pg14+（已测试非常快无延迟）&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="#" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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://www.postgresql.org/message-id/flat/17716-1fe42e7b44fc2f25%40postgresql.org" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/message-id/flat/17716-1fe42e7b44fc2f25%40postgresql.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=d7eb52d71" target="_blank" rel="noreferrer"&gt;https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=d7eb52d71&lt;/a&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>我的年终总结2024</title><link>https://lastdba.com/2025/01/11/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932024/</link><pubDate>Sat, 11 Jan 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/01/11/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932024/</guid><description>&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;2023对我来说是全面学习pg的一年，而2024就是全面运维pg的一年。其实还有一些资料我很想dive in但是一直没有时间搞，今年主要是案例分析，基础知识学习只有靠时不时的补补了。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;2023对我来说是全面学习pg的一年，而2024就是全面运维pg的一年。其实还有一些资料我很想dive in但是一直没有时间搞，今年主要是案例分析，基础知识学习只有靠时不时的补补了。&lt;/p&gt;
&lt;p&gt;年中的时候有一个关于“dba会不会被云时代淘汰的”的讨论，这次讨论我印象很深，我后面也想了很多东西，想了很多为什么别人事情很少，但是我的dba事情这么多之类的，甚至最后还去云计算群里面battle了一圈，确实有收获，不同的立场会有意想不到的结果。battle的结论可能只有一个：dba在给领导们提供1510情绪价值。&lt;/p&gt;
&lt;p&gt;无论对还是错吧，今年可以在很多文章中看到对dba职业的思考。dba再继续走传统dba模式肯定是死路一条了，现在的dba会更倾向业务数据层运维，或者上升到架构设计，专注数据库的专家型dba的职位其实是很少的。&lt;/p&gt;

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


&lt;img src="https://lastdba.com/img/csdn/4961d50ee1c3.jpg" alt="image" /&gt;&lt;/p&gt;
&lt;p&gt;再说下为何执着看书（23年也说过···）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;阅读带来的价值短期无法估量&lt;/li&gt;
&lt;li&gt;阅读带来的知识充值愉悦感&lt;/li&gt;
&lt;li&gt;学习是一种信仰。尤瓦尔有个观点是：相信科学实际上也是一种信仰。我选择相信这个信仰，至少24年以及短期可见的未来是这样&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我的书单大概分成3类：pg类、大技术范围类、课外书。有中文也有英文，有纸质有电子。&lt;/p&gt;
&lt;p&gt;今年继续来个书单排名，类别不同横向对比有点扯，就分类对比吧。再次备注，这些书单是“从头到尾”式的冲着finish去的，当reference的看的书不在此列。&lt;/p&gt;
&lt;p&gt;2024年pg书单（按喜好排名）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;《PostgreSQL数据库内核分析》，思路框架清晰，就是版本有点老&lt;/li&gt;
&lt;li&gt;《快速掌握PostgreSQL版本新特性》，这应该是我今年最喜欢的pg书，因为它全程&lt;strong&gt;无废话&lt;/strong&gt;，看着舒服&lt;/li&gt;
&lt;li&gt;《PostgreSQL指南 内幕探索》，这本书我本来想放到第一位，但是因为有interdb在线免费文档，我甚至都不推荐这本书，排在这里是因为interdb太棒了，替身在这里当神供着&lt;/li&gt;
&lt;li&gt;《PostgreSQL修炼之道 从小工到专家 第二版》，很细但也很多，建议快速翻完找到里面的重点，不要逗留太久&lt;/li&gt;
&lt;li&gt;《PostgreSQL技术内幕 事务处理深度探索》，事务是pg的基础，也是我的源码入门基础&lt;/li&gt;
&lt;li&gt;《PostgreSQL实战》，里面的实战还是很值得借鉴&lt;/li&gt;
&lt;li&gt;《PostgreSQL 16 Administration Cookbook》，不推荐，目录框架看着不错，内容很空，不推荐在这本书上浪费时间&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2024年大技术范围类书单（按喜好排名）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;《DDIA-v2 设计数据密集型应用（第二版）》，好到不知道从何说起，棒到我专门写了&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E2%80%94%E2%80%94DDIA-v2%20%E8%AE%BE%E8%AE%A1%E6%95%B0%E6%8D%AE%E5%AF%86%E9%9B%86%E5%9E%8B%E5%BA%94%E7%94%A8%EF%BC%88%E7%AC%AC%E4%BA%8C%E7%89%88%EF%BC%89.md" target="_blank" rel="noreferrer"&gt;读书笔记&lt;/a&gt;（我今年唯一的读书笔记文章），相见恨晚&lt;/li&gt;
&lt;li&gt;《数据库简史》，读史真的可以明鉴，数据库的故事从这里开始，有些技术的东西都想得更明白了。&lt;/li&gt;
&lt;li&gt;《ITIL 4 与devops 服务管理认证指南（第二版）》，IT服务管理的经典，提升一下对运维这个角色的理解，和我工作息息相关的这些东西又是怎么来的，哪些又是不符合实际以及为什么没有应用上？可以领悟到很多东西。&lt;/li&gt;
&lt;li&gt;《云原生Kubernetes》，硬核，另一个赛道&lt;/li&gt;
&lt;li&gt;《深入浅出Docker》，理解容器和容器历史还不错，容器本身的知识其实不多&lt;/li&gt;
&lt;li&gt;《鸟哥的linux私房菜》，sorry我确实没有读过这本经典，补番来的。里面的写做思路很值得借鉴，缺点在于很多东西对于我的职能来说无法受益&lt;/li&gt;
&lt;li&gt;《机器学习》，排在这里不是这本书不好，是很难看懂，大概到1/4的时候就放弃了，这本书让我了解了我的智力上限，我很难过&lt;/li&gt;
&lt;li&gt;《从零搭建向量数据库》，看源码应该去github&lt;/li&gt;
&lt;li&gt;《深入理解go语言》，理解了个寂寞&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2024年课外书单（按喜好排名）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;《癌症楼》，这本书上半年早期就看完了，看的时候就觉得，不出意外这本书今年能排第一。诺贝尔文学奖，实至名归&lt;/li&gt;
&lt;li&gt;《亲密关系》，理解和恋人、和朋友、和老板的关系，论文风格，扎实，我喜欢&lt;/li&gt;
&lt;li&gt;《上帝掷骰子吗？量子物理史话》，别的不说，写作风格极其提供情绪价值，让我想一直看下去，没几天就把他看完了&lt;/li&gt;
&lt;li&gt;《The Worlds I see》，AI 李飞飞的自传，一个成都长大的姑娘到水生活热美利坚冒险，最后执掌谷歌AI的故事，顺便讲述了一下AI的发展历史&lt;/li&gt;
&lt;li&gt;《今日简史》，尤瓦尔三部曲最后一部，前两本都看完甚是喜欢，但是这一本感觉一般般，算是有始有终吧&lt;/li&gt;
&lt;li&gt;《the old man and the sea》，不好评价，我喜欢它的气质，但不喜欢它的内容&lt;/li&gt;
&lt;li&gt;《朝问道》，这是一本刘慈欣的短篇小说集，某天在图书馆因为第一篇短篇把它买下了，买回来发现其他短篇都很boring很幼稚，感觉被骗了&lt;/li&gt;
&lt;li&gt;《西游记》，暴论：唐僧的身世都讲不明白，乱起八遭、稀里糊涂。看了点就放弃了（我去年对《三国演义》的评价是很高的）&lt;/li&gt;
&lt;/ol&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%8d%9a%e5%ae%a2%e5%92%8c%e5%85%ac%e4%bc%97%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;2024年的创作文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pg技术 21篇&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其他技术 2篇&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;读书笔记 1篇&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无用文章 1篇&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今年只写了25篇文章，写作数量较去年明显下降了。&lt;/p&gt;
&lt;p&gt;公众号followers 600，虽然人不多，但是我相信每一个都是有品位的人 &amp;#x1f638;&lt;/p&gt;
&lt;p&gt;写技术文章其实挺累的，花的时间要比想象的多的多，不过在写作过程中确实可以学到东西，完作的成就感还是有的。应为要对文章负责，不懂的事情我自己不会去乱写。至于理解有误而出现的错误，其实也是正常现象，没人能保证5年后的自己不怼现在的自己，在当前状态下写对就行了。&lt;/p&gt;
&lt;p&gt;今年写作内容上，放弃了课外书的读后感写作，去年写的挺多的，写读后感很费时间而且价值很低，低情绪价值的事情自然就放弃了。其实我每年的写作内容都有差别，目前来看就PG库技术类文章是永恒不变坚持创作的，其他类型的都没那么稳定。这也算正常吧，本来写博客就是为了写数据库，其他领域如果没有应用场景的话，短暂试探期过去就不会再接触了。&lt;/p&gt;
&lt;p&gt;还想吐槽一点，国内的博客平台只对文章数量感兴趣，跟我的写作风格十分不契合，我一篇文章都是手敲的上万字，我是宁缺毋滥型博主。所以也懒得管了，准备25年放弃CSDN，就发发github和公众号得了。&lt;/p&gt;
&lt;p&gt;CSDN我2017年就开始写了，当初写博客那会就没几个好用的博客托管平台。现在来看CSDN 社区交互为0，上面文章绝大部分都很挫，我自己都不想搜到CSDN的文章，就像虽然有7、8年感情的初恋，该分手还是得分手。&lt;/p&gt;
&lt;p&gt;24年的发文途径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSDN博客：&lt;a href="https://liuzhilong.blog.csdn.net/" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;墨天轮 liuzhilong62&lt;/li&gt;
&lt;li&gt;github：https://github.com/liuzhilong62/blogs&lt;/li&gt;
&lt;li&gt;公众号：破斯特贵斯库儿&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;25年预计途径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;github：https://github.com/liuzhilong62/blogs&lt;/li&gt;
&lt;li&gt;公众号：破斯特贵斯库儿&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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;我似乎每年都在说work-learning balance···由于今年工作量剧增，有段时间甚至都没办法学习了，balance已经被击碎。没有时间学习我是无法接受的，所以后面调整了一下自己的作息时间（感谢《原子习惯》这本书，我太爱了），总算能挤出一点时间来学习。其实只要周围没人，学习效率就是高的。&lt;/p&gt;
&lt;p&gt;收集了一下今年我比较认可的话：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不要让别人成为那你任务链上的依赖 &amp;ndash;heisenberg.liu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要执行力的方案一般都是简单的方案 &amp;ndash;heisenberg.liu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有落地的事情等于没有做 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自己去想办法解决问题，而不是等别人回消息 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重要的事情马上就做，等一会都是做不了的 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要做重复的低价值的事情，多想想这个需求源头的上下文 &amp;ndash;heisenberg.liu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要在屎里淘金，想办法搞优质信息源 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SRE需要配置最佳默认参数的能力，也需要批量修改这些参数的能力 &amp;ndash;《企业云计算》&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;杂活做的越多，杂活就越多 &amp;ndash;heisenberg.liu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sre 50%的时间用来运维，50%的时间用来研发 &amp;ndash;《企业云计算》&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;过早的优化是万恶之源，过早的代码抽象也是万恶之源 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;人脑接收知识的速度是有限的 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果有人不让你看书，那就离开这个人，或者离开这个环境 &amp;ndash;heisenberg.liu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;做知识库的团队是混子 &amp;ndash;somebody&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;标准的价值是由客户来决定的 &amp;ndash;《ITIL 4 》&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;英雄主义：长时间工作并独立排查故障，长时间的工作也会对工作本身感到倦怠。凡事想成为英雄的人，他们只对自己的成就感兴趣，对团队协调工作置若罔闻 &amp;ndash;《ITIL 4 》&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不是所有问题都需要定位根因，取决于问题发生频率和故障范围 &amp;ndash;《ITIL 4 》&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;回顾了一下2023年的自己定的计划，总共就2个一个都没完成，KPI达成率&lt;strong&gt;0% ​&lt;/strong&gt;&amp;#x1f604;&lt;/p&gt;
&lt;p&gt;结合敏捷运维、敏捷项目管理、OKR的思想，我在年初就给自己定下全年计划，就是不合理的。回想去年、前年，我有些计划就是半路杀出并在优先级上pk过了其他任务。并且有些任务无法完成，这是应该是一个正常状态。so，不给自己立太多flag。&lt;/p&gt;
&lt;p&gt;2025年计划：&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;li&gt;PG···没想好还要怎么做&lt;/li&gt;
&lt;li&gt;想办法重拾健身&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>pg数据库运维经验2024</title><link>https://lastdba.com/2025/01/08/pg%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%90%E7%BB%B4%E7%BB%8F%E9%AA%8C2024/</link><pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/01/08/pg%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%90%E7%BB%B4%E7%BB%8F%E9%AA%8C2024/</guid><description>&lt;p&gt;这篇文章主要是讲pg运维常见问题，两三年见一次的疑难杂症就不说了。&lt;/p&gt;
&lt;p&gt;主要是技术性运维总结，主打通俗易懂和快速上手，尽量避免源码层面等深入分析。&lt;/p&gt;

&lt;h2 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%80%a7%e8%83%bd%e4%b8%8e%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92" 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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e7%aa%81%e5%8f%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg官方不支持hint功能，并且计划永远不支持！
PG社区大概是这个意思&amp;quot;我们的优化器是完美的，如果当前执行计划不够优秀，那是开发不懂优化”。&lt;/p&gt;</description><content:encoded>&lt;p&gt;这篇文章主要是讲pg运维常见问题，两三年见一次的疑难杂症就不说了。&lt;/p&gt;
&lt;p&gt;主要是技术性运维总结，主打通俗易懂和快速上手，尽量避免源码层面等深入分析。&lt;/p&gt;

&lt;h2 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%80%a7%e8%83%bd%e4%b8%8e%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92" 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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e7%aa%81%e5%8f%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg官方不支持hint功能，并且计划永远不支持！
PG社区大概是这个意思&amp;quot;我们的优化器是完美的，如果当前执行计划不够优秀，那是开发不懂优化”。&lt;/p&gt;
&lt;p&gt;不管pg社区怎么看，生产环境的执行计划突变问题是时常发生的，而且我们没有ORACLE那样原生且丰富的绑定执行计划手段来处理问题。这对生产运维来说是一个挑战，例如：某天早上，一个敏感的sql突然执行计划改变了，运行时间从0.1s上涨到1s，由于SQL有一定的并发导致数据库的cpu打满，业务感知明显。由于我们没有绑定执行计划的手段，此时我们唯二能做的快速恢复手段就是1.收集统计信息 2.scale up扩容cpu。&lt;/p&gt;
&lt;p&gt;这里的快速恢复手段有个问题是：收集统计信息一定有用吗？好的DBA可以找到优化器中的关键问题步骤在哪，但是也不能快速脑补一个完整的执行计划出来，特别是SQL比较复杂的时候。收集统计信息这个恢复手段，实际上把SQL优化问题返还给了优化器，同时相信优化器是可以胜任这个工作的。虽然这看上去有些扯，但是在PG数据库中，绝大部分情况是有用的（对于已知收集统计信息无用的场景，见&amp;quot;order by limit问题&amp;quot;小节)。&lt;/p&gt;
&lt;p&gt;为什么执行计划会突变且性能变差？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;执行计划是基于成本的，而成本又基于统计信息，统计信息又是永远滞后的&lt;/li&gt;
&lt;li&gt;SQL足够复杂的话执行路径就会有非常多种，优化器会根据成本选择最优的一条&lt;/li&gt;
&lt;li&gt;PG提供了很多优化器参数可以调整，目的是以适配本地硬件设置（如&lt;code&gt;seq_page_cost&lt;/code&gt;
,&lt;code&gt;effective_cache_size&lt;/code&gt;等等），我们可以通过调整这些参数来微调优化器的倾向。但是这些参数太底层，虽然理论上是有优化空间，但都是牵一发而动全身的。特别是数据库上线后，调整这些参数就是一个极高风险的操作。从这些参数设置的理由来看，也可以推测执行计划不可能是100%完美的，因为优化器的推理也依赖环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即使强如oracle，提供了各种方案稳固执行计划，它也保证不了SQL 100%不会出问题，因为SQL、数据、统计信息、绑定变量等等都是动态的。
对于PGer来说还想不了那么远，不过我们可以尽可能地考虑稳定执行计划的方案，如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要用太多的表连接。表越多可能的执行计划也就越多，甚至&lt;a href="https://www.postgresql.org/docs/16/geqo-pg-intro.html" target="_blank" rel="noreferrer"&gt;PG GEQO&lt;/a&gt;会放弃生成所有的执行计划，这就降低了最优执行计划的概率&lt;/li&gt;
&lt;li&gt;不要写太过复杂的SQL。还要考虑SQL可能是框架（ORM）生成而不是业务人员手工编写的，这样的SQL一般是为了实现某个目标而几乎不考虑SQL的简洁性和阅读性，优化起来十分棘手。&lt;/li&gt;
&lt;li&gt;不要乱建索引以迷惑优化器，必须有明确的目标&lt;/li&gt;
&lt;li&gt;调整表的统计信息搜集阈值&lt;code&gt;autovacuum_vacuum_scale_factor&lt;/code&gt;（参考“统计信息收集不及时”小节）&lt;/li&gt;
&lt;li&gt;可以使用pg_hint_plan来提示优化器。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;pg_hint_plan
 &lt;div id="pg_hint_plan" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_hint_plan" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/ossc-db/pg_hint_plan" target="_blank" rel="noreferrer"&gt;pg_hint_plan&lt;/a&gt;是第三方插件，通过hint来提示优化器选择正确的执行计划。
&lt;strong&gt;pg_hint_plan支持：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指定扫描方式（如索引扫描）、连接方式（NL/HASH/MERGE）、连接顺序、memoize、指定预估行数、并行、GUC参数&lt;/li&gt;
&lt;li&gt;通过hint_plan.hints绑定sql的执行计划，不需要改变业务SQL文本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;pg_hint_plan缺陷：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;子查询、外部表、CTE、视图、PL/SQL等有使用限制&lt;/li&gt;
&lt;li&gt;compute_query_id会把hint当做注释忽略&lt;/li&gt;
&lt;li&gt;未知的bug&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个插件虽然在持续更新，但是（我）还没有找到大规模生产应用的案例。另外我们在少量的生产应用场景中发现了一些问题，执行计划可能不会生效，这跟jdbc执行计划缓存有关系，至于有没有其他问题暂时不好下定论。
总之pg_hint_plan是个好东西，但是生产大规模部署有待商榷。推荐静待其变，可以试用但不要对它产生依赖性。&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%bb%9f%e8%ae%a1%e4%bf%a1%e6%81%af%e6%94%b6%e9%9b%86%e4%b8%8d%e5%8f%8a%e6%97%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;统计信息是sql优化的基础，pg统计信息并不难但还是有很多人没弄明白。&lt;/p&gt;
&lt;p&gt;pg的统计信息主要看这3个表：pg_class、pg_stat_all_tables、pg_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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- pg_class看pages和tuples
&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,relpages,reltuples::bigint &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;lzlpg&amp;#39;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;187501&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reltuples &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6000032&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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_stat_all_tables看活元组、死元组，上次统计信息收集时间
&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,n_live_tup,n_dead_tup,last_analyze,last_autoanalyze &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_all_tables &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;lzlpg&amp;#39;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_live_tup &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6000032&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_dead_tup &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;last_analyze &lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;15&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;553057&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;last_autoanalyze &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--pg_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;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stats &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; tablename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;lzlpg&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; attname&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:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;schemaname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tablename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;attname &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;inherited &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;null_frac &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;avg_width &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_distinct &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;most_common_vals &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;most_common_freqs &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;histogram_bounds &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;correlation &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;most_common_elems &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;most_common_elem_freqs &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;elem_count_histogram &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;统计信息过久很有可能会造成SQL执行计划改变，引起SQL性能问题。
此时就需要查看&lt;code&gt;pg_stat_all_tables&lt;/code&gt;表的&lt;code&gt;last_autovacuum&lt;/code&gt;,&lt;code&gt;last_autoanalyze&lt;/code&gt;时间来判断表的收集是不是滞后了。&lt;/p&gt;
&lt;p&gt;为什么要调整？因为表的统计信息收集阈值&lt;code&gt;autovacuum_analyze_scale_factor&lt;/code&gt; 默认值是0.1，也就是数据变化达到10%时，才会收集统计信息。例如一个10亿数据的表，数据变化达到1亿时才会收集，频率可能太低了。&lt;/p&gt;
&lt;p&gt;应该结合是否核心业务表、SQL表连接个数、SQL复杂度、表访问频率、月初越界问题、数据倾斜问题等判断是否需要针对性的调整表的&lt;code&gt;autovacuum_vacuum_scale_factor&lt;/code&gt;,&lt;code&gt;autovacuum_analyze_scale_factor&lt;/code&gt;以提高统计信息收集频率，降低SQL执行计划突变的概率，同时也要避免收集过于频繁老是跑vacuum浪费资源。&lt;/p&gt;
&lt;p&gt;到底该调整到多少？举个例子：&lt;/p&gt;
&lt;p&gt;以月表（或月分区表）及SQL统计当天数据为例，由于&lt;code&gt;autovacuum_analyze_scale_factor =0.1&lt;/code&gt;，月表在前10天基本每天都会收集，在第12天左右的时候可能不会收集，这时候统计信息可能越界，执行计划就有可能有问题。为了保证月表在每月的10-31天都收集统计信息，应该把&lt;code&gt;autovacuum_analyze_scale_factor&lt;/code&gt;设置得小于&lt;code&gt;0.03&lt;/code&gt;，所以推荐&lt;code&gt;autovacuum_analyze_scale_factor=0.02&lt;/code&gt;&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;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;autovacuum_vacuum_scale_factor&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.2&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.04&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;autovacuum_analyze_scale_factor&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.02&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="#%e4%bc%98%e5%8c%96%e5%99%a8%e5%8f%af%e8%83%bd%e9%80%89%e6%8b%a9%e5%85%b6%e4%bb%96%e7%b4%a2%e5%bc%95%e8%80%8c%e4%b8%8d%e6%98%af%e4%b8%bb%e9%94%ae" 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;&lt;span style="color:#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; t1(a char(&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;) &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;1000&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; t1 &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text),md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text) &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;10000&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxa &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1(a);
&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; idxb &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1(b);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;analyze&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:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;||&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;--a、b字段有同样的过滤性，但是优化器没有走主键而是走普通索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxb &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1 (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;41&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;43&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;2008&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;045&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;046&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::bpchar)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::bpchar)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--强行走主键，cost只多一丢丢丢
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;||&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxa &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1 (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;41&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;2008&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;079&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;079&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::bpchar)&lt;span style="color:#f92672"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((b)::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 style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared &lt;span style="color:#66d9ef"&gt;read&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;虽然a、b两个字段类型和选择率是一样的，但是优化器没有选择走主键而是走了普通索引，从cost来看走主键的cost多了0.01。&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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; t1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (autovacuum_enabled &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;off&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:#66d9ef"&gt;into&lt;/span&gt; t1 &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text),&lt;span style="color:#e6db74"&gt;&amp;#39;repeat&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;20001&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;30000&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;--b=&amp;#39;repeat&amp;#39;过滤性很差，但是还是走b字段索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;repeat&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxb &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1 (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;41&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;43&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;2008&lt;/span&gt;) (actual time&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;823&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;824&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;repeat&amp;#39;&lt;/span&gt;::bpchar)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::bpchar)
&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;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2511&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; t1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; b&lt;span style="color:#f92672"&gt;||&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;repeat&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idxa &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t1 (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;41&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;2008&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;041&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;041&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;qwer&amp;#39;&lt;/span&gt;::bpchar)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((b)::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 style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;repeat&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;即使真实的过滤性不好，优化器仍然选择走普通索引，但是走普通索引的效率要低很多，因为shared hit=2511远大于shared hit=3。如果是敏感业务sql或者数据量比较大的时候，就会有问题，这个问题在生产中也常见。
解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手动收集统计信息；调高统计信息收集频率&lt;/li&gt;
&lt;li&gt;pg_hint_plan&lt;/li&gt;
&lt;li&gt;改写sql让其不能走普通索引&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;order by limit问题
 &lt;div id="order-by-limit问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#order-by-limit%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;order by limit的sql已是一个常见的问题了，网上案例和分析也比较多，这里就不详细分析了（可以参考我写这篇&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%A1%88%E4%BE%8B/ORDER%20BY%20limit%2010%E6%AF%94ORDER%20BY%20limit%20100%E6%9B%B4%E6%85%A2.md" target="_blank" rel="noreferrer"&gt;ORDER BY limit 10比ORDER BY limit 100更慢&lt;/a&gt;)。
根本原因在于优化器目前无法评估数据以索引顺序存放在表的哪个位置，可能数据靠后而导致扫描过多的数据才返回limit。注意这个场景不是仅出现在order by limit，任何可以用到排序操作的+limit都可能有这个问题，如：group by +limit、distinct +limit、merge..&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决办法：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL改造：添加表达式防止走到排序列的索引上（含主键），如 &lt;code&gt;order by ''||col1 limit xxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;创建复合索引：创建排序字段的索引字段的复合索引，优化器可能会选择这个索引，效率一般都比排序字段的索引高。这个方案也不用动sql。&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="#%e8%a1%a8%e8%86%a8%e8%83%80" 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%90%e4%b8%aa%e4%b8%9c%e8%a5%bf%e9%98%bb%e6%ad%a2%e4%ba%86%e6%ad%bb%e5%85%83%e7%bb%84%e5%9b%9e%e6%94%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;抛开autovacuum配置问题和一些边缘场景，常见的阻塞是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;长事务。注意：不是同一个表的长事务也会阻止死元组回收；查询语句也会造成这个问题&lt;/li&gt;
&lt;li&gt;复制槽。复制槽延迟和死的复制槽会造成这个问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两种常见都是比较好解决的，1.terminate长事务会话 2.删除复制槽或者让消费端分析消费为什么这么慢。&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="#update%e5%b9%b6%e5%8f%91%e9%ab%98%e5%af%bc%e8%87%b4%e8%a1%a8%e8%86%a8%e8%83%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;不同于某个东西阻止vacuum回收死元组，频繁的update导致表膨胀是因为死元组生成的速度快于vacuum回收的速度。一般来说这个场景的表的&lt;code&gt;pg_stat_all_tables.n_tup_upd&lt;/code&gt;比较高，如果是因为表膨胀问题发现需要做repack的话，最好同时评估下是不是表的写入量大，应避免反复的手工repack。此时就需要调整表/索引的fillfactor参数。&lt;/p&gt;
&lt;p&gt;原理参考这篇文章&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/%E4%BB%8E%E5%BE%88%E6%85%A2%E7%9A%84%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%E6%89%AB%E6%8F%8F%E5%88%B0%E7%B4%A2%E5%BC%95%E8%86%A8%E8%83%80.md" target="_blank" rel="noreferrer"&gt;从很慢的唯一索引扫描到索引膨胀&lt;/a&gt;，结论我直接copy下来：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;fillfactor原理：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;fillfactor相当于表或索引的水位线，在INSERT数据时，插入到page的fillfactor线就到下一页去插入。fillfactor本身是为了给update留一定的空间，防止update频繁的去寻找新的page。&lt;/p&gt;
&lt;p&gt;虽然表和索引都有fillfactor，他们的目的是一样的（为了update），但是具体细节有很大区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表：如果表的某个page上还有留有空间，那么update可以在这个page中进行，不需要申请新的page或者到其他有空闲空间的page上去。不仅如此，因为PG 独有的HOT特性，页内更新不会更新索引，当然也就会减缓索引膨胀&lt;/li&gt;
&lt;li&gt;索引：不同的数据行或者相同数据行的页外更新，会新生成索引条目。fillfactor给索引页留下余量，会极大的减缓索引分离问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，fillfactor的设置跟业务模型是息息相关的，如果数据类似日志那样是递增且完全没有更新的，那么表和索引的fillfactor设置成100无可厚非。但是大部分业务表总是有更新的，表和索引fillfactor就不应该设置成100，如果是频繁的update，那么fillfactor应该设置得更低。
然而，pg默认的fillfactor如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表默认 fillfactor=100&lt;/li&gt;
&lt;li&gt;索引默认 fillfactor=90&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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-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; lzlpg &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (fillfactor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&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;index&lt;/span&gt; lzlpg_pkey &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (fillfactor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;70&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生效，对存量page需要做repack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--repack:
&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:#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;.nohup pg_repack &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#75715e"&gt;--table lzlpg -p 6666 -no-kill-backend &amp;gt; pgrepack_lzlpg_log.log 2&amp;gt;&amp;amp;1 &amp;amp;&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="#%e9%95%bf%e4%ba%8b%e5%8a%a1%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;长事务的知识点没有多少，及时告警及时处理就行了，但长事务问题绝对值得拿出来单独批斗。&lt;/p&gt;
&lt;p&gt;长事务会导致许多问题，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;锁不释放导致应用阻塞&lt;/li&gt;
&lt;li&gt;wal不回收导致磁盘告警&lt;/li&gt;
&lt;li&gt;死元组不回收导致sql性能下降&lt;/li&gt;
&lt;li&gt;还有些奇葩性能问题跟长事务相关&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;pg的长事务危害要比oracle、mysql来得大的多，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%ad%90%e4%ba%8b%e5%8a%a1%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;“Subtransactions are basically cursed. Rip em out.”&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;子事务会造成很多问题，也是我们常踩的坑，在行业中也经常遇到子事务导致的问题。&lt;/p&gt;
&lt;p&gt;行业踩坑记录：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pganalyze.com/blog/5mins-postgres-17-configurable-slru-cache" target="_blank" rel="noreferrer"&gt;Waiting for Postgres 17: Configurable SLRU cache sizes for increased performance&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://knowledge.enterprisedb.com/hc/en-us/articles/13523268146972-Subtransactions-overflow-and-the-performance-cliff" target="_blank" rel="noreferrer"&gt;Subtransactions-overflow-and-the-performance-cliff&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;Why we spent the last month eliminating PostgreSQL subtransactions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;子事务的出现：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PL/pgSQL&lt;/code&gt; functions containing a block with an &lt;strong&gt;exception&lt;/strong&gt; clause&lt;/li&gt;
&lt;li&gt;&lt;code&gt;savepoints&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;JDBC+&lt;a href="https://jdbc.postgresql.org/documentation/use/" target="_blank" rel="noreferrer"&gt;autosave=always&lt;/a&gt; （默认&lt;code&gt;autosave=never&lt;/code&gt; ）&lt;/li&gt;
&lt;li&gt;ODBC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意OGG使用ODBC驱动，ODBC不能关闭子事务。&lt;/p&gt;
&lt;p&gt;GaussDB提供的ODBC可以关闭子事务，参数&lt;a href="https://support.huaweicloud.com/intl/en-us/centralized-devg-v8-gaussdb/gaussdb-42-0098.html" target="_blank" rel="noreferrer"&gt;ForExtensionConnector&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;所以我们可以建议应用使用子事务不超过64个，但很难建议他们不去使用OGG，因为脱O意味着使用依赖OGG 的数据同步工具。&lt;/p&gt;
&lt;p&gt;子事务问题出现的场景和现象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1(+)个长事务+子事务溢出+高并发业务，性能急剧下降&lt;/li&gt;
&lt;li&gt;子事务溢出(64+)，性能稍微下降&lt;/li&gt;
&lt;li&gt;子事务溢出(64+)+multixact，性能急剧下降&lt;/li&gt;
&lt;li&gt;1(+)个长事务+1(+)个子事务，查询库性能急剧下降&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;pg17的提升：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SLRU是clog、multixact、subtrans等用来在共享内存中管理事务关系的。相关的源码定义如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#75715e"&gt;#define NUM_SUBTRANS_BUFFERS	32 &lt;/span&gt;&lt;span style="color:#75715e"&gt;//SLRU页面个数32个，这是共享内存中的
&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;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Each backend advertises up to PGPROC_MAX_CACHED_SUBXIDS TransactionIds
&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 non-aborted subtransactions of its current top transaction. These
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * have to be treated as running XIDs by other backends.
&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 also keep track of whether the cache overflowed (ie, the transaction 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; * generated at least one subtransaction that didn&amp;#39;t fit in the 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; * If none of the caches have overflowed, we can assume that an XID that&amp;#39;s 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; * listed anywhere in the PGPROC array is not a running transaction. Else 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; * have to look at 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;//超过64个则溢出，each backend
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg17对SLRU的提升：
新增GUC参数可以配置SLRU槽的个数，拆分现有的SLRU锁由单个集中控制锁变为多个bank锁&lt;/p&gt;
&lt;p&gt;提升效果：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d712858437e4.png" alt="image.png" /&gt;
（https://www.pgevents.ca/events/pgconfdev2024/sessions/session/53/slides/27/SLRU%20Performance%20Issues.pdf）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;子事务处理方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发规范：不要用&lt;code&gt;savepoints&lt;/code&gt;，考虑&lt;code&gt;on conflict&lt;/code&gt;语法处理写入冲突&lt;/li&gt;
&lt;li&gt;开发规范：不要用&lt;code&gt;exception&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;开发规范：确保jdbc&lt;em&gt;没有&lt;/em&gt;显示打开&lt;code&gt;autosave=always&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;添加监控：针对性的监控&lt;code&gt;pg_stat_slru&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;添加监控：针对性的监控&lt;code&gt;SAVEPOINT&lt;/code&gt; and &lt;code&gt;EXCEPTION &lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CDC规范：谨慎使用ODBC，OGG或其他用到ODBC的工具，需要切割事务，一个大事务最高子事务个数上限为5W&lt;/li&gt;
&lt;li&gt;升级版本：升级到PG17&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%b9%b6%e5%8f%91%e4%b8%8e%e6%80%a7%e8%83%bd" 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%bf%ab%e7%85%a7%e5%92%8c%e5%b9%b6%e5%8f%91%e5%8f%82%e6%95%b0%e8%b0%83%e6%95%b4" 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;&lt;code&gt;old_snapshot_threshold&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;cpu&lt;/td&gt;
 &lt;td&gt;-1（社区版）&lt;/td&gt;
 &lt;td&gt;-1&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;max_parallel_workers_per_gather&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;cpu&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;old_snapshot_threshold&lt;/code&gt;参数打开&lt;em&gt;很容易&lt;/em&gt;引起性能问题，网上资料已经很多了自行搜索，哪怕是需要重启数据库，也强烈推荐关闭参数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;max_parallel_workers_per_gather&lt;/code&gt; 参数会自动开墙大sql的并行，但是并行为2效率不会成比例提高2倍，参数建议在特殊场景下使用，如跑批时显示指定并行度。由于不需要重启，也就顺手一改的事。&lt;/p&gt;
&lt;p&gt;关闭&lt;code&gt;old_snapshot_threshold&lt;/code&gt;会不会有问题？&lt;/p&gt;
&lt;p&gt;不会。&lt;code&gt;old_snapshot_threshold&lt;/code&gt;参数目的是为了限制长事务，因为pg长事务很容易引起性能问题，但是参数本身也会引发性能问题就得不偿失了。&lt;/p&gt;
&lt;p&gt;处理长事务可以很多手段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;长事务监控。这是最重要的，而且监控已经比较成熟了。&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;statement_timeout&lt;/code&gt;，默认0&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;transaction_timeout&lt;/code&gt; ，默认0，版本17=+支持&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;lock_timeout&lt;/code&gt; ，默认0，DDL语句建议会话级别开启&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;idle_in_transaction_session_timeout&lt;/code&gt;，默认0，已开启2h&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;idle_session_timeout&lt;/code&gt; ，默认0，这个场景没用&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;高并发提交导致LWLOCK:WALWrite
 &lt;div id="高并发提交导致lwlockwalwrite" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%ab%98%e5%b9%b6%e5%8f%91%e6%8f%90%e4%ba%a4%e5%af%bc%e8%87%b4lwlockwalwrite" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%A1%88%E4%BE%8B/%E6%A1%88%E4%BE%8B-insert%20value%E5%81%B6%E5%8F%91%E6%85%A2%E5%88%86%E6%9E%90.md" target="_blank" rel="noreferrer"&gt;案例-insert value偶发慢分析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;记忆点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IO:WALWrite只有1个，而LWLOCK:WALWrite有几十个&lt;/li&gt;
&lt;li&gt;不能直接看到LWLOCK的blocking chain，但是我可以从源码中得知，LWLOCK:WALWrite在等待IO:WALWrite&lt;/li&gt;
&lt;li&gt;在这种并发高的小事务场景中，提高wal buffer内存大小理论上效果不会太理想&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;会引起什么问题？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并发写入阻塞，写入接口变慢，活动会话可能上涨&lt;/li&gt;
&lt;li&gt;高并发小事务无法压榨磁盘IO&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;li&gt;分析FPI，尝试减少FPI（参考FPI小节）&lt;/li&gt;
&lt;li&gt;组提交（&lt;a href="https://www.postgresql.org/docs/17/runtime-config-wal.html#GUC-COMMIT-DELAY" target="_blank" rel="noreferrer"&gt;待研究&lt;/a&gt;）&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;WAL与延迟
 &lt;div id="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="#wal%e4%b8%8e%e5%bb%b6%e8%bf%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;FPI与checkpoint参数
 &lt;div id="fpi与checkpoint参数" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fpi%e4%b8%8echeckpoint%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg的wal FPI发生在checkpoint后首次写入相关page时，所以checkpoint越频繁FPI出现的概率越高。&lt;/p&gt;
&lt;p&gt;checkpoint频率与两个参数相关：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checkpoint_timeout&lt;/li&gt;
&lt;li&gt;max_wal_size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理如下：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0197be136174.png" alt="image.png" /&gt;
(Egor Rogov PoStgreSQL 14 Internals)&lt;/p&gt;
&lt;p&gt;max_wal_size默认是1GB，这对于负载高的库来说太小了，一般来说可以调大这个参数以减少FPI。&lt;/p&gt;
&lt;p&gt;checkpoint_timeout默认是5分钟，目前来看比较合理。&lt;/p&gt;

&lt;h3 class="relative group"&gt;FPI与离散写
 &lt;div id="fpi与离散写" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fpi%e4%b8%8e%e7%a6%bb%e6%95%a3%e5%86%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;即使调大了checkpoint的间隔，可能还是会有 FPI 问题，此时需要再排查业务是否有 UUID 离散写情况，可能需要业务改造为 sequence 或其他 UUID 方案。&lt;/p&gt;
&lt;p&gt;找到具体索引示例：&lt;/p&gt;
&lt;p&gt;1.查看FPI是否严重&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--stats=record&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;pg_waldump -z --stats&lt;span style="color:#f92672"&gt;=&lt;/span&gt;record 00000001000001860000001B&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.排序哪个rel的FPW比较多&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_waldump 00000001000001860000001B|grep FPW|awk -F &lt;span style="color:#e6db74"&gt;&amp;#39;:&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;{print $7}&amp;#39;&lt;/span&gt;|awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;|sort -n|uniq -c |sort -r|head -10&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="#%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e5%92%8c%e5%a4%8d%e5%88%b6%e6%a7%bd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;逻辑复制问题非常多，也是社区重点优化项之一，几乎每个版本都有很大提升。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/PostgreSQL%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6.md" target="_blank" rel="noreferrer"&gt;逻辑复制和复制槽基础知识&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;spill问题
 &lt;div id="spill问题" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#spill%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%A1%88%E4%BE%8B/PG%E8%B5%B7%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cspill%E5%AF%BC%E8%87%B4%E8%B5%B7%E5%BA%93%E6%85%A2%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.md" target="_blank" rel="noreferrer"&gt;PG起库逻辑和spill导致起库慢问题分析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;spill记忆点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;spill是逻辑解码的时候内存放不下事务信息了所以放到磁盘，spill文件存放的就是事务信息&lt;/li&gt;
&lt;li&gt;每个walsender都有独立的解码，所以每个逻辑复制都有自己的spill&lt;/li&gt;
&lt;li&gt;大事物spill时，会有大spill文件，一般文件数比较少&lt;/li&gt;
&lt;li&gt;子事务spill时，每个子事务对应一个spill文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;版本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PG12及以前是写死的4096条changes&lt;/li&gt;
&lt;li&gt;PG13新增&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;参数，可调整内存大小以减少spill概率&lt;/li&gt;
&lt;li&gt;PG14及以后支持流式复制Streaming&lt;/li&gt;
&lt;li&gt;触发流式复制也需要一定的条件，所以即使有流式复制也可能会发生spill&lt;/li&gt;
&lt;li&gt;PG17新增&lt;code&gt;debug_logical_replication_streaming&lt;/code&gt;参数以强制触发流式传输&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;walsender阻止停库
 &lt;div id="walsender阻止停库" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#walsender%e9%98%bb%e6%ad%a2%e5%81%9c%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%A1%88%E4%BE%8B/PG%E5%81%9C%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cwalsender%E9%98%BB%E6%AD%A2%E5%81%9C%E5%BA%93%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.md" target="_blank" rel="noreferrer"&gt;PG停库逻辑和walsender阻止停库问题分析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其实任意进程不退出都会阻止停库，问题在于哪些比较容易搞出事。从停库代码流程来看archiver、walsender会常阻止停库，因为他们在停库阶段会做最后一次归档or日志传递。


&lt;img src="https://camo.githubusercontent.com/45e44c384cdf1c41caf9d2018076cf420cd48c9d49be1b2078262b4303be2627/68747470733a2f2f6f73732d656d637370726f642d7075626c69632e6d6f64622e70726f2f696d6167652f656469746f722f32303235303130342d313837353338333238343037393830343431365f343538372e706e67" alt="" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果停库卡在walsender，尝试用&lt;code&gt;kill&lt;/code&gt;杀掉walsender而不是直接&lt;code&gt;kill -9&lt;/code&gt; ，此时checkpoint还没有跑完，强制停库会造成不一致停库。注意强制停库也最好用&lt;code&gt;pg_ctl stop -D $PGDATA -m i&lt;/code&gt;来停库，而不是直接&lt;code&gt;kill -9 &lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果停库卡在archiver，可以直接kill -9，因为checkpoint已经跑完了，库是一致性状态&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" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/PostgreSQL%E5%88%86%E5%8C%BA%E8%A1%A8.md" target="_blank" rel="noreferrer"&gt;分区表基础知识&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;由于PG分区表其实是很有特点的，有些特性知识不研究就不知道，开发一般弄不明白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%88%86%e5%8c%ba%e8%a1%a8%e7%88%b6%e8%a1%a8%e5%92%8c%e5%ad%90%e8%a1%a8%e7%b4%a2%e5%bc%95%e4%b8%8d%e4%b8%80%e8%87%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于创建子分区不规范，很多索引是在子表上建的（实际上不应该单独在子表上建索引），也没有做 ”所有子表创建索引+attach索引“的操作，导致父表其实没有索引或没用有效索引。父表因为没有数据所以其上没索引对业务没有影响，影响的是新建子分区时，只会继承父表索引，导致新的子表可能会缺少索引。&lt;/p&gt;
&lt;p&gt;父表失效索引比较好处理，参考&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/PostgreSQL%E5%88%86%E5%8C%BA%E8%A1%A8.md#%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" 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:#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;p&gt;父表没有主键比较难处理，参考&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E5%86%85%E5%8A%9F%E4%BF%AE%E7%82%BC/PostgreSQL%E5%88%86%E5%8C%BA%E8%A1%A8.md#%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" target="_blank" rel="noreferrer"&gt;分区表添加主键和唯一索引&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;添加主键在主表上申请&lt;code&gt;AccessExclusiveLock&lt;/code&gt;，阻塞一切。 分区表上添加索引很慢，主键又会造成后续的阻塞，目前没有影响较小的在分区表上添加主键的办法。虽然没有达到目的，可以考虑用“attach唯一索引+非空约束”的办法；或者只能申请较长的停分区表业务，等待创建索引完成；或者通过第三方同步工具将数据插入一个带主键的分区表。&lt;/p&gt;

&lt;h3 class="relative group"&gt;滥用default分区
 &lt;div id="滥用default分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%bb%a5%e7%94%a8default%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/liuzhilong62/blogs/blob/main/PostgreSQL%E6%A1%88%E4%BE%8B/%E6%B2%A1%E6%9C%89%E9%98%BB%E5%A1%9E%E4%B8%BA%E4%BB%80%E4%B9%88partition%20of%E5%88%9B%E5%BB%BA%E5%AD%90%E5%88%86%E5%8C%BA%E5%BE%88%E6%85%A2%EF%BC%9F.md" target="_blank" rel="noreferrer"&gt;default分区过大导致parition of创建子分区长期阻塞&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;原因很简单：分区表新增子分区时，由于建分区的语句需要校验default分区中的数据，保证新分区数据范围与default分区的现有数据不冲突，导致&lt;code&gt;create table partition of&lt;/code&gt;读取了大量的default分区数据，新建分区一直未完成。随后阻塞扩大，业务数据无法查询和写入。&lt;/p&gt;
&lt;p&gt;default分区滥用是普遍的问题！社区pg本来也没有提供interval分区功能，开发哪天忘记创建分区了，数据就跑到default分区，也不会有任何报错和告警。但是日复一日···default分区就越来越大，最后发版建分区搞出问题。&lt;/p&gt;
&lt;p&gt;default分区过大不能一直这么放着，虽然attach建分区可以避开阻塞问题，但出于各种角度考虑还是需要排这个雷。&lt;/p&gt;
&lt;p&gt;default分区数据处理方案1：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;detach default子分区，然后合理创建子分区，再将default表数据回插到分区表中。&lt;/li&gt;
&lt;li&gt;如有必要，可在detach且创建合理子分区后，创建一个空的default分区，以保持业务数据的连续性。&lt;/li&gt;
&lt;li&gt;注意detach跟attach不同，detach需要主表的8级锁。PG14支持detach concurrently，但不能有default分区。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;default分区数据处理方案2：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;detach default子分区，然后合理创建子分区，detached后的default表attach成普通子分区，需要注意range的范围。&lt;/li&gt;
&lt;li&gt;如有必要，可在detach且创建合理子分区后，创建一个空的default分区，以保持业务数据的连续性。&lt;/li&gt;
&lt;li&gt;注意detach跟attach不同，detach需要主表的8级锁。PG14支持detach concurrently，但不能有default分区。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;default分区数据处理方案3：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;新建表所有数据通过dts同步&lt;/li&gt;
&lt;li&gt;rename表&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;方案3看起来是最矬的，但是我个人最推荐。原因是如果你的手里有5套库需要处理，那么可以用精湛方案没问题，如果你的手里有200套库需要处理，那么要投入的人力成本，dts应该是最佳落地方案。&lt;/p&gt;

&lt;h3 class="relative group"&gt;分区表select权限丢失导致执行计划异常
 &lt;div id="分区表select权限丢失导致执行计划异常" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a8select%e6%9d%83%e9%99%90%e4%b8%a2%e5%a4%b1%e5%af%bc%e8%87%b4%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e5%bc%82%e5%b8%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;用户对分区子表没用select权限，会导致用户执行的sql不能访问子表的统计信息，从而导致执行计划异常。正常partition of创建的分区表是不带select权限的，从主表访问数据可以访问到，所以这是范围比较大的问题。&lt;/p&gt;
&lt;p&gt;解决方案&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让云平台解决，自动化处理&lt;/li&gt;
&lt;li&gt;落地select子分区权限的开发规范&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;高并发分区全扫描和LWLock:lockmanager
 &lt;div id="高并发分区全扫描和lwlocklockmanager" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%ab%98%e5%b9%b6%e5%8f%91%e5%88%86%e5%8c%ba%e5%85%a8%e6%89%ab%e6%8f%8f%e5%92%8clwlocklockmanager" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这也是一个很常见的问题！&lt;/p&gt;
&lt;p&gt;推荐看下aws的文档，写的很清楚了：&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/wait-event.lw-lock-manager.html" target="_blank" rel="noreferrer"&gt;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/wait-event.lw-lock-manager.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题现象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;活动会话暴涨&lt;/li&gt;
&lt;li&gt;LWLock:lockmanager等待事件严重&lt;/li&gt;
&lt;li&gt;数据库性能cliff&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发生场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sql查询多个分区&lt;/li&gt;
&lt;li&gt;该sql并发较高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;记忆点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fastpath锁机制本身是为了“弱锁”快速访问，提升数据库并发而设计的&lt;/li&gt;
&lt;li&gt;fastpath锁等级小于等于3。即是select、select for xxx、DML才能使用（弱锁便是锁模式必须小于&lt;code&gt;ShareUpdateExclusiveLock&lt;/code&gt;，也就是1、2、3级锁有机会使用到fastpath）。换句话说就是为了正常业务都受益&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FP_LOCK_SLOTS_PER_BACKEND&lt;/code&gt;，本地进程持有fastpath的锁不超过16个，超过16就要到内存中去获得锁，&lt;code&gt;LWLock:lockmanager&lt;/code&gt;在此时产生&lt;/li&gt;
&lt;li&gt;不仅是表，每个被访问的索引都要加锁&lt;/li&gt;
&lt;li&gt;这个问题跟分区数量没有多大关系，即便分区比较少也可能触发&lt;code&gt;LWLock:lockmanager&lt;/code&gt;等待导致性能下降&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以计算一下，如果一个分区表上有1个主键和2个普通索引，多少个分区就会用不到fastpath？&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;16&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:#ae81ff"&gt;3&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:#ae81ff"&gt;1&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:#ae81ff"&gt;1&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:#ae81ff"&gt;3&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个子分区的全分区扫描就会可能会出现这个LWLock:lockmanager等待了。&lt;/p&gt;
&lt;p&gt;如果是普通表的话，表上建16个索引也会用不到fastpath。&lt;/p&gt;
&lt;p&gt;解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于表不是特别大的，合并分区成普通表&lt;/li&gt;
&lt;li&gt;sql加入分区过滤条件&lt;/li&gt;
&lt;li&gt;减少索引（比较没用，因为一般子分区数就超过16个了）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;难点：&lt;/p&gt;
&lt;p&gt;在oracle脱O到PG库的场景中，由于oracle支持全局索引，主键和唯一索引可以不带分区键，到pg后主键和唯一索引必须要带分区键。&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;idxlzl(primarykey) &lt;span style="color:#75715e"&gt;--oracle
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;idxlzl(primarykey,partitionkey) &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;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:#66d9ef"&gt;select&lt;/span&gt; col &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; primarykey&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个场景要推动业务在这个sql上添加分区条件吗？很难。阻力在于“我已经传入主键了，你还要我怎样？如果我什么数据都知道，我还要查数据库吗？”&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="#%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e5%af%b9%e8%b1%a1%e8%bf%87%e5%a4%9a%e5%af%bc%e8%87%b4relcache%e8%bf%87%e5%a4%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;记忆点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;relcache保留relation相关的元数据：oid、pg_class、分区表、子事务、行安全策略、统计信息、索引元数据、am等等。&lt;/li&gt;
&lt;li&gt;每个会话都有自己的(rel)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;解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;减少对象，特别是要检查分区表子分区数是否太多了&lt;/li&gt;
&lt;li&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%e7%a2%8e%e7%89%87%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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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/meminfo|grep whatyouneed
&lt;/span&gt;&lt;/span&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## cg内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/opt/cgtools/cginfo -t perf -s mem 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重点关注 pgscand/s直接内存回收指标，一般几万就代表有问题&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; -e &lt;span style="color:#e6db74"&gt;&amp;#34;09:00:00&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;#min_free_kbytes设置:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /proc/sys/vm/min_free_kbytes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#所有进程的物理总内存使用量：&lt;/span&gt;
&lt;/span&gt;&lt;/span&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;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#某进程PSS内存：&lt;/span&gt;
&lt;/span&gt;&lt;/span&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;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#某进程的RSS内存 ：&lt;/span&gt;
&lt;/span&gt;&lt;/span&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;&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/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;min_free_kbytes：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://camo.githubusercontent.com/ec10b5b4434febdb6675545e2beaa60646be264db9fb8259cd787cdd4771054b/68747470733a2f2f692d626c6f672e6373646e696d672e636e2f626c6f675f6d6967726174652f35653435303466323634303231633438386438613637623962333665666265322e706e67" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;（&lt;a href="https://vivani.net/2022/06/14/linux-kernel-tuning-page-allocation-failure/" target="_blank" rel="noreferrer"&gt;https://vivani.net/2022/06/14/linux-kernel-tuning-page-allocation-failure/&lt;/a&gt;)&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;&lt;code&gt;vm.min_free_kbytes&lt;/code&gt;也就是min_pages线，十分重要的操作系统参数。非常低的值会阻止系统有效地回收内存，这可能会导致系统崩溃并中断服务。太高的值会增加系统回收活动，造成分配延迟，这可能导致系统立即进入内存不足状态。&lt;/p&gt;
&lt;p&gt;优化效果：&lt;/p&gt;
&lt;p&gt;min_free_kbytes调大+部署非业务时段drop cache，问题已经少很多了。&lt;/p&gt;
&lt;p&gt;为什么是调高min_free_kbytes？&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This is used to force the Linux VM to keep a minimum number of kilobytes free. The VM uses this number to compute a watermark[WMARK_MIN] value for each lowmem zone in the system. Each lowmem zone gets a number of reserved free pages based &lt;strong&gt;proportionally&lt;/strong&gt; on its size.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/sysctl/vm.html#min-free-kbytes" target="_blank" rel="noreferrer"&gt;min_free_kbytes&lt;/a&gt;调高的本质不是为了把对应的min page线提高已更高概率地触发直接内存回收，而是因为low page线在linux7以前是无法调整的，只能通过调高min page线以等比例的提高low page线以更容易触发异步回收，并给直接内存回收的触发创造缓冲时间。&lt;/p&gt;
&lt;p&gt;Redhat 8 版本增加了2个内存参数来优化内存回收 ：watermark_scale_factor 可以在不调整min_free_kbytes情况下，抬高水位线。&lt;/p&gt;
&lt;p&gt;建议开启大页：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大页在业务（pg库）申请连续内存的时候性能较好&lt;/li&gt;
&lt;li&gt;大页也有助于减少page cache大小&lt;/li&gt;
&lt;li&gt;shared_buffer可使用大页，需开启Huge_pages和操作系统已开启大页&lt;/li&gt;
&lt;li&gt;生产开启了大页的库，性能有提升，问题更少&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Managing.html#AuroraPostgreSQL.Managing.HugePages" target="_blank" rel="noreferrer"&gt;aws大页标准&lt;/a&gt;：除了几个测试套餐外，其他均默认开启大页且不可关闭&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;Huge_pages&lt;/code&gt; parameter is turned on by default for all DB instance classes other than t3.medium,db.t3.large,db.t4g.medium,db.t4g.large instance classes. You can&amp;rsquo;t change the &lt;code&gt;huge_pages&lt;/code&gt; parameter value or turn off this feature in the supported instance classes of Aurora PostgreSQL.&lt;/p&gt;
&lt;/blockquote&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%92%8c%e4%b8%bb%e6%9c%ba%e5%86%85%e5%ad%98%e9%94%99%e4%bd%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;cgroup中的内存达到cg内存限制后，kswapd 进程会优先回收cg中的内存，云主机售卖资源和cgroup配置，可能存在主机空闲内存在水位之上，而cg内存紧张，主机层面的pages_low ，导致kswapd 不会异步回收主机内存也不会回收cg内存，最终是通过触发直接回收内存CG中的DB内存需求。&lt;/p&gt;
&lt;p&gt;​	根因在于cgroup中没有单独的free page内存管理机制。&lt;/p&gt;
&lt;p&gt;​ 这种情况只能把cg内存调高，云主机内存更多的超卖，以达更容易达到主机的pages_low。&lt;/p&gt;

&lt;h3 class="relative group"&gt;shared_buffer和pagecache
 &lt;div id="shared_buffer和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="#shared_buffer%e5%92%8cpagecache" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg是double buffer机制，目前还没有direct IO。&lt;/p&gt;
&lt;p&gt;double buffer是指DB shared buffer一层共享内存，OS pagecache一层共享内存。在真实场景中，pagecache一般远大于shared buffer，而pagecache又是算在cgroup mem中的，没有算到监控cg内存中···&lt;/p&gt;
&lt;p&gt;总之，要留足内存给pagecache使用，shared buffer不要超过太大（目前来看20GB足够），除非可以明显观察到等待事件中有buffer mapping相关内存等待，不然不要去调太大。&lt;/p&gt;

&lt;h3 class="relative group"&gt;work_mem无法限制hash join/hash aggregate使用的内存
 &lt;div id="work_mem无法限制hash-joinhash-aggregate使用的内存" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#work_mem%e6%97%a0%e6%b3%95%e9%99%90%e5%88%b6hash-joinhash-aggregate%e4%bd%bf%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;hash_mem_multiplier&lt;/strong&gt; 用于限制基于hash-based operations的内存大小（应该包括hash join，hash agg等），限制是&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。&lt;/p&gt;
&lt;p&gt;在pg13以前虽然可以限制&lt;code&gt;work mem&lt;/code&gt;，但是无法限制1个query使用了多少个hash操作，所以pg13增加了这个参数。也就是说13以前，是很难限制hash table的内存的。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在pg12-的生产环境中找到消耗300G内存的一个会话，罪魁祸首就是低版本没有hash table限制和执行计划错误的使用hash table&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%85%b6%e4%bb%96%e9%97%ae%e9%a2%98" 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%8e%92%e4%bb%96%e5%a4%87%e4%bb%bd%e5%92%8c%e8%b5%b7%e5%ba%93%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;正常来说，数据库停库再起库，起库的位置从pg_controldata中的LSN位置获取，但是如果PGDATA目录下有一个&lt;code&gt;backup_label&lt;/code&gt;文件，启动位置LSN会从&lt;code&gt;backup_label&lt;/code&gt;文件获取。&lt;/p&gt;
&lt;p&gt;会引起什么问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;磁盘快照直接打的是data目录快照，label文件有可能在里面，如果库大备份时间长的话，起库时间就很长&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大问题：某些原因生产停库后，库启动会很久。根因在于起库的LSN应该从controldata中获取，而不是备份中&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;版本变化：&lt;/p&gt;
&lt;p&gt;pg13:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg_start_backup()&lt;/code&gt;
&lt;code&gt;pg_stop_backup()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;支持排他和非排他模式，默认就是排他模式。排他模式会在start的时候在data目录下创建&lt;code&gt;backup_label&lt;/code&gt;文件，stop的时候会清理。非排他模式start的时候不会创建label文件，stop的时候返回label信息。&lt;/p&gt;
&lt;p&gt;pg15:
&lt;code&gt;pg_backup_start()&lt;/code&gt;
&lt;code&gt;pg_backup_stop()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;函数名称变化，&lt;strong&gt;移除了排他备份模式&lt;/strong&gt;。不会在启动备份的时候写&lt;code&gt;backup_label&lt;/code&gt;文件，而是在结束备份的时候写入到备份区域。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg_stat_activty无法查询
 &lt;div id="pg_stat_activty无法查询" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_activty%e6%97%a0%e6%b3%95%e6%9f%a5%e8%af%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;现象：&lt;/p&gt;
&lt;p&gt;pg_stat_activty无法查询&lt;/p&gt;
&lt;p&gt;当时的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:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; pgstat_read_current_status () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; pgstat.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3642&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;x0000000000727181 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pgstat_read_current_status () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; pgstat.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2788&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; pgstat_fetch_stat_numbackends () &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; pgstat.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2789&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000083f2ee &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pg_stat_get_activity (fcinfo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x25c2d98) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; pgstatfuncs.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;575&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;x000000000065058f &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ExecMakeTableFunctionResult (setexpr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x25b1d28, econtext&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x25b1c48, argContext&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;, expectedDesc&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x2545218, randomAccess&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; execSRF.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;234&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x00000000006609dc &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; FunctionNext (node&lt;span style="color:#f92672"&gt;=&lt;/span&gt;node&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;x25b1b38) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; nodeFunctionscan.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;94&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;x000000000065110c &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ExecScanFetch (recheckMtd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x660700 &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;FunctionRecheck&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, accessMtd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x660720 &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;FunctionNext&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:#ae81ff"&gt;0&lt;/span&gt;x25b1b38) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; execScan.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;133&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;code&gt;st_changecount&lt;/code&gt;成为奇数进入死循环。&lt;/p&gt;
&lt;p&gt;什么场景会触发？OOM（可复现），backend异常退出（可能），terminate（maybe）；这三个场景不代表一定会造成这个问题。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/message-id/5979.1557543440%40sss.pgh.pa.us" target="_blank" rel="noreferrer"&gt;社区邮件&lt;/a&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="#%e8%bf%9e%e6%8e%a5%e9%97%ae%e9%a2%98%e5%92%8c%e8%bf%9e%e6%8e%a5%e6%b1%a0%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;IO error报错
 &lt;div id="io-error报错" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#io-error%e6%8a%a5%e9%94%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;IO error报错一般是业务层与数据库连接断开，业务层仍在使用已断连的连接导致的报错。
该问题出现比较频繁，而且由于整个链路上涉及的组件多、知识域宽，所以诊断起来比较困难，以下做一个简单总结。&lt;/p&gt;
&lt;p&gt;已知的主动断连场景：&lt;/p&gt;
&lt;p&gt;1.hikari &lt;code&gt;maxLifetime&lt;/code&gt;
现象：会话保持时间与参数一致。 可能报错原因：业务显示事务执行 select 未提交，连接池断开会话，业务报&lt;code&gt; io error；could not 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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg.datasouce.maxLifetime&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.druid timeout
现象：业务 sql 执行超 20s 后连接断开&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;spring.datasource.dynamic.druid.socketTimeout=20000 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spring.datasource.dynamic.druid.connectTimeout=20000 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;改为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spring.datasource.socketTimeout=3600000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spring.datasource.connectTimeout=3600000 &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%9a%e5%8a%a1%e5%ae%b9%e5%99%a8%e6%89%a9%e5%ae%b9%e5%92%8c%e6%95%b0%e6%8d%ae%e5%ba%93%e8%bf%9e%e6%8e%a5%e4%b8%8a%e9%99%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;业务横向扩容和pg库的连接瓶颈：&lt;/p&gt;
&lt;p&gt;HikariCP目前已是SpringBoot默认的连接池，伴随着SpringBoot和微服务的普及，HikariCP 的使用也越来越多。业务每扩容一个pod，数据库连接数都会上涨。原因在于&lt;code&gt;maximumPoolSize&lt;/code&gt;虽然每个pod中配置没有动，但业务节点横向扩展了。从已有节点数、增加节点数、现有数据库连接总数可以成比例的计算出来数据库的空闲连接会加多少。&lt;/p&gt;
&lt;p&gt;应用可以无状态的横向扩容，但是数据库不是，pg的连接上限参数&lt;code&gt;max_connections&lt;/code&gt;，应用成倍的扩容是有可能造成idle连接数就打满了。&lt;code&gt;max_connections&lt;/code&gt;的调整是个很麻烦的工作因为要重启数据库生效。&lt;/p&gt;
&lt;p&gt;pg库连接上限:&lt;/p&gt;
&lt;p&gt;还有一个点在于，业务无限横向扩容，&lt;code&gt;max_connections&lt;/code&gt;应该随云实例套餐调整而调整，但是可以无限往上调整吗？很明显不是的。pg库，无论什么库，idle连接越多性能都会下降。&lt;/p&gt;
&lt;p&gt;可参考&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Managing.html#AuroraPostgreSQL.Managing.MaxConnections" target="_blank" rel="noreferrer"&gt;AWS的做法&lt;/a&gt;：
&lt;code&gt;max_connections&lt;/code&gt;与套餐相关，最大值&lt;code&gt;5000 ,LEAST({DBInstanceClassMemory/9531392},5000)&lt;/code&gt;.这可以减少人力运维连接数，也给出了比较合理的最大值&lt;/p&gt;</content:encoded></item><item><title>PG起库逻辑和spill导致起库慢问题分析</title><link>https://lastdba.com/2025/01/04/pg%E8%B5%B7%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cspill%E5%AF%BC%E8%87%B4%E8%B5%B7%E5%BA%93%E6%85%A2%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/</link><pubDate>Sat, 04 Jan 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/01/04/pg%E8%B5%B7%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cspill%E5%AF%BC%E8%87%B4%E8%B5%B7%E5%BA%93%E6%85%A2%E9%97%AE%E9%A2%98%E5%88%86%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="#%e9%97%ae%e9%a2%98%e7%8e%b0%e8%b1%a1-%e8%b5%b7%e5%ba%93%e7%bc%93%e6%85%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;版本pg13.2&lt;/p&gt;
&lt;p&gt;数据库启动缓慢，startup进程在读取spill文件，文件名在变化。查看spill文件也很慢，ls -l最后跑出来有800w个文件spill文件。&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-%e8%b5%b7%e5%ba%93%e7%bc%93%e6%85%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;版本pg13.2&lt;/p&gt;
&lt;p&gt;数据库启动缓慢，startup进程在读取spill文件，文件名在变化。查看spill文件也很慢，ls -l最后跑出来有800w个文件spill文件。&lt;/p&gt;

&lt;h2 class="relative group"&gt;为什么有上千万个spill文件
 &lt;div id="为什么有上千万个spill文件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e6%9c%89%e4%b8%8a%e5%8d%83%e4%b8%87%e4%b8%aaspill%e6%96%87%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;wal段和LSN的含义
 &lt;div id="wal段和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="#wal%e6%ae%b5%e5%92%8clsn%e7%9a%84%e5%90%ab%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;

&lt;h4 class="relative group"&gt;LSN
 &lt;div id="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="#lsn" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;LSN总体是一个64位的bigint，LSN实际长这样&lt;code&gt;42D3B/1732C540&lt;/code&gt;（hex），斜杠&lt;code&gt;/&lt;/code&gt;前是32位逻辑日志号，&lt;code&gt;/&lt;/code&gt;后32位是段号+块号+块内偏移。这4个部分分别是：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;32位&lt;/th&gt;
 &lt;th&gt;8位&lt;/th&gt;
 &lt;th&gt;11位&lt;/th&gt;
 &lt;th&gt;13位&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;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;块内偏移 8192=2^13&lt;/p&gt;
&lt;p&gt;块号=16M（默认wal段大小）/8192&lt;/p&gt;

&lt;h4 class="relative group"&gt;wal segment
 &lt;div id="wal-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="#wal-segment" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;wal文件名由3组16进制数字组成。&lt;/p&gt;
&lt;p&gt;以8k的wal文件&lt;code&gt;0000000300042D3B00000002&lt;/code&gt;为例：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;32位&lt;/th&gt;
 &lt;th&gt;32位&lt;/th&gt;
 &lt;th&gt;32位&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;timeline&lt;/td&gt;
 &lt;td&gt;逻辑日志号&lt;/td&gt;
 &lt;td&gt;日志段号&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;00000003&lt;/td&gt;
 &lt;td&gt;00042D3B&lt;/td&gt;
 &lt;td&gt;00000002&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以看出LSN可以定位到wal文件名及文件中offset位置。&lt;/p&gt;
&lt;p&gt;其中，LSN斜杠&lt;code&gt;/&lt;/code&gt;前是逻辑日志号，斜杠&lt;code&gt;/&lt;/code&gt;后8位的日志段号下面都会用到。&lt;/p&gt;

&lt;h3 class="relative group"&gt;spill文件名转换
 &lt;div id="spill文件名转换" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#spill%e6%96%87%e4%bb%b6%e5%90%8d%e8%bd%ac%e6%8d%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;复制槽名：logical_ex2209_rep&lt;/p&gt;
&lt;p&gt;spill文件名：xid-407989064-lsn-42D1E-20000000.spill&lt;/p&gt;
&lt;p&gt;42D1E不是一个完整的LSN，不能直接用&lt;code&gt;pg_walfile_name&lt;/code&gt;来定位wal文件名。42D1E是一个逻辑日志号，如果直接过滤文件名含42D1E的wal文件，可以找到16个wal文件。&lt;/p&gt;
&lt;p&gt;能否通过数字20000000定位到wal日志段号从而定位到哪一个文件呢？&lt;/p&gt;
&lt;p&gt;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/%s和xid-%u-lsn比较好理解，就是复制槽名称和xid。后面的&lt;code&gt;recptr&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; * Pointer to a location in the XLOG. These pointers are 64 bits wide,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * because we don&amp;#39;t want them ever to overflow.
&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; uint64 XLogRecPtr;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;XLogSegNoOffsetToRecPtr&lt;/code&gt;是通过wal日志段号、段大小、offset计算LSN:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; (dest) = (segno) * (wal_segsz_bytes) + (offset)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;XLogRecPtr就是LSN！那么&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(uint32) (recptr &amp;gt;&amp;gt; 32)&lt;/code&gt;表示取LSN前32位，&lt;code&gt;(uint32) recptr)&lt;/code&gt;取LSN后32位。&lt;/p&gt;
&lt;p&gt;LSN前32位也就是刚才看到的LSN前半段，lsn-42D1E；LSN后32位实际上信息多了，这里只要LSN后32位中的前几位的段号即可。&lt;/p&gt;
&lt;p&gt;因为传入的offset=0，也传入了segno，那么根本不需要wal日志段内偏移量信息，就可以计算出dest的值。wal_segsz_bytes的真实值是128M*1014*1024，将&lt;code&gt;XLogSegNoOffsetToRecPtr&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;segno&lt;span style="color:#f92672"&gt;=&lt;/span&gt; dest&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;128&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;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- 再把16进制20000000转化下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;segno&lt;span style="color:#f92672"&gt;=&lt;/span&gt; x&lt;span style="color:#e6db74"&gt;&amp;#39;20000000&amp;#39;&lt;/span&gt;::int&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;128&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;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;segno&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;可以从式子算出日志段号segno，也就可以定位到wal文件号了。&lt;/p&gt;
&lt;p&gt;所以，这里的spill文件名：xid-407989064-lsn-42D1E-20000000.spill对应的wal文件为&lt;/p&gt;
&lt;p&gt;逻辑日志号=42D1E，段号=04：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 42D1E*04
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000200042D1E00000004&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_waldump可以看到xid 407989064在里面。&lt;/p&gt;
&lt;p&gt;实际上wal大小在实例创建后也是固定的，即(128*1024*1024)是一个常量，那么segno跟(uint32) recptr绝对相关，但不相等。也就是说切换一个wal日志就会切换一个spill。&lt;/p&gt;
&lt;p&gt;最后总结&lt;strong&gt;spill文件生成规则&lt;/strong&gt;如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一个事务id，如果跨wal就会产生多个spill。如：一个不含子事务的大事务跨越3个wal，就会对应3个spill文件&lt;/li&gt;
&lt;li&gt;不同的事务id对应不同的spill。如：1000w个子事务对应1000w个spill&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;spill文件名结构xid-407989064-lsn-42D1E-20000000.spill：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;xid&lt;/th&gt;
 &lt;th&gt;lsn前32位；即wal逻辑日志号&lt;/th&gt;
 &lt;th&gt;由wal日志段号换算；不等于段号&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;xid-407989064&lt;/td&gt;
 &lt;td&gt;lsn-42D1E&lt;/td&gt;
 &lt;td&gt;20000000&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-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;
&lt;/span&gt;&lt;/span&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;$ ll |head -100
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;40000276&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;184&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 15:20 state
&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;196&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:25 xid-407989064-lsn-42D1E-0.spill
&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;208&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:25 xid-407989064-lsn-42D1E-20000000.spill
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;540&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 16:44 xid-407989064-lsn-42D2A-D0000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989065-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989066-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989068-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989070-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989072-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989076-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989079-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989080-lsn-42D1D-C8000000.spill
&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;152&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 13:09 xid-407989082-lsn-42D1D-C8000000.spill
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;postgres@lzlhost /myhost/liuzhilong/pg_replslot/logical_ex9e15_rep&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll |awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $9}&amp;#39;&lt;/span&gt;|awk -F &lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;|sort|uniq -c|wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;10000003&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;postgres@lzlhost /myhost/liuzhilong/pg_replslot/logical_ex9e15_rep&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll |wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;10000070&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;所以我们在实际环境中看到了10000070个文件，文件的distinct xid有10000003个，也就是说1个父事务跨越约70个wal文件，这个父事务有1000w个子事务。&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%a4%8d%e5%88%b6%e6%a7%bd%e6%ba%a2%e5%87%ba%e6%b5%8b%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;logical_decoding_work_mem &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;MB &lt;span style="color:#f92672"&gt;#&lt;/span&gt;pg_ctl reload
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_segment_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt; MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--source
&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; replication_table (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id BIGSERIAL &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; column1 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; column2 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; column3 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&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_test &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; replication_table ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--dest
&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; replication_table (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id BIGSERIAL &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; column1 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; column2 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; column3 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&gt;&lt;/span&gt;&lt;span style="display: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 style="color:#66d9ef"&gt;CONNECTION&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;host=127.0.0.1 port=8094 dbname=lzl user=lzl password=qwer&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PUBLICATION pub_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:#75715e"&gt;--source
&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_replication_slots;&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%a4%a7%e4%ba%8b%e5%8a%a1%e6%97%a0%e5%ad%90%e4%ba%8b%e5%8a%a1%e5%a4%8d%e5%88%b6%e8%a1%a8%e6%ba%a2%e5%87%ba%e6%b5%8b%e8%af%95" 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 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;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; replication_table(column1,column2,column3) 
&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:#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 style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&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;1000000&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--复制槽溢出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;331924&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 postgres postgres 184 Dec 9 20:22 state
&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 postgres postgres 88226964 Dec 9 20:22 xid-5074343-lsn-163-38000000.spill
&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 postgres postgres 119698488 Dec 9 20:22 xid-5074343-lsn-163-40000000.spill&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，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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pid,usename,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,reply_time &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; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sent_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; write_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; flush_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replay_lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; write_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; flush_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replay_lag &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reply_time 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;163525&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;163&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4996&lt;/span&gt;E1C8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;163&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4996&lt;/span&gt;E1C8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;163&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4996&lt;/span&gt;E1C8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;163&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4996&lt;/span&gt;E1C8 &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:#ae81ff"&gt;2024&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:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14769&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:#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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pid,usename,pg_wal_lsn_diff(pg_current_wal_lsn(),sent_lsn) diff_sent_mb,pg_wal_lsn_diff(pg_current_wal_lsn(),write_lsn) diff_write_mb,pg_wal_lsn_diff(pg_current_wal_lsn(),flush_lsn) diff_flush_mb,pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn) diff_replay_mb,pg_walfile_name_offset(sent_lsn) sentoffset,pg_walfile_name_offset(write_lsn) writeoffset,pg_walfile_name_offset(flush_lsn) flush_lsn &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; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; diff_sent_mb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; diff_write_mb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; diff_flush_mb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; diff_replay_mb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sentoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; writeoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; flush_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; &lt;span style="color:#ae81ff"&gt;163525&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;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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000010000016300000009&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;26665416&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000010000016300000009&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;26665416&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;mypg&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg8094&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_replslot&lt;span style="color:#f92672"&gt;/&lt;/span&gt;sub_test]&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;357392&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 postgres postgres 184 Dec 9 20:23 state
&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 postgres postgres 88226964 Dec 9 20:22 xid-5074343-lsn-163-38000000.spill
&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 postgres postgres 137696328 Dec 9 20:23 xid-5074343-lsn-163-40000000.spill
&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 postgres postgres 26076708 Dec 9 20:23 xid-5074343-lsn-163-48000000.spill
&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;mypg&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg8094&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_replslot&lt;span style="color:#f92672"&gt;/&lt;/span&gt;sub_test]&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 postgres postgres 184 Dec 9 20:25 state2666
&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;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%e4%ba%8b%e5%8a%a1%e6%97%a0%e5%ad%90%e4%ba%8b%e5%8a%a1%e9%9d%9e%e5%a4%8d%e5%88%b6%e8%a1%a8%e6%ba%a2%e5%87%ba%e6%b5%8b%e8%af%95" 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;--source 创建一个不相干的表，准备写入数据
&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; no_replication_table (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id BIGSERIAL &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; column1 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; column2 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; column3 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;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;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; no_replication_table(column1,column2,column3) 
&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:#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 style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&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;1000000&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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;lzldb:MYINST:&lt;span style="color:#ae81ff"&gt;8094&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt;mypg&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg8094&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_replslot&lt;span style="color:#f92672"&gt;/&lt;/span&gt;sub_test]&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;357492&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 postgres postgres 184 Dec 9 20:09 state
&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 postgres postgres 107511456 Dec 9 20:08 xid-5074106-lsn-163-28000000.spill
&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 postgres postgres 137698804 Dec 9 20:09 xid-5074106-lsn-163-30000000.spill
&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 postgres postgres 4308444 Dec 9 20:09 xid-5074106-lsn-163-38000000.spill&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%a4%a7%e4%ba%8b%e5%8a%a1%e5%ad%90%e4%ba%8b%e5%8a%a1%e9%9d%9e%e5%a4%8d%e5%88%b6%e8%a1%a8%e6%ba%a2%e5%87%ba%e6%b5%8b%e8%af%95" 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;## 一次insert一行，每个insert一个子事务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;begin;&amp;#34;&lt;/span&gt;&amp;gt;subtx.sql
&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; i in &lt;span style="color:#f92672"&gt;{&lt;/span&gt;1..1000000&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;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;savepoint p&lt;/span&gt;$i&lt;span style="color:#e6db74"&gt;;&amp;#34;&lt;/span&gt;&amp;gt;&amp;gt;subtx.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;insert into no_replication_table(column1,column2,column3) select &amp;#39;a&amp;#39;,&amp;#39;b&amp;#39;,&amp;#39;c&amp;#39;;&amp;#34;&lt;/span&gt;&amp;gt;&amp;gt;subtx.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nohup psql -d lzl -f subtx.sql &amp;amp;&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;#执行过程中，观察到溢出80w+文件&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;/myhost/pg8094/data/pg_replslot/sub_test&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll |wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;823749&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;/myhost/pg8094/data/pg_replslot/sub_test&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll |head -10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;1099532&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;184&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:10 state
&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;1236&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:10 xid-5519686-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519687-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519688-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519689-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519690-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519691-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519692-lsn-163-70000000.spill
&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;252&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 xid-5519693-lsn-163-70000000.spill&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="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%90%af%e5%8a%a8%e6%85%a2%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;startup进程起库流程分析
 &lt;div id="startup进程起库流程分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#startup%e8%bf%9b%e7%a8%8b%e8%b5%b7%e5%ba%93%e6%b5%81%e7%a8%8b%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这里以堆栈编号逐栈解析起库流程：&lt;/p&gt;
&lt;p&gt;11：&lt;code&gt;main&lt;/code&gt;：没啥好说的&lt;/p&gt;
&lt;p&gt;10：&lt;code&gt;PostmasterMain&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;在主循环前，会先调用起库流程&lt;code&gt; StartupPID = StartupDataBase();&lt;/code&gt;本质上是调用&lt;code&gt;StartChildProcess(StartupProcess)&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 StartupDataBase()		StartChildProcess(StartupProcess)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;9：&lt;code&gt;StartChildProcess&lt;/code&gt; ：fork一个进程。该进程为启动postmaster的辅助进程，正常的子进程启动都走这个逻辑，在这一步fork。这里的入参&lt;code&gt;AuxProcType&lt;/code&gt;=StartupProcess&lt;/p&gt;
&lt;p&gt;8：&lt;code&gt;AuxiliaryProcessMain&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;因为&lt;code&gt;MyAuxProcType&lt;/code&gt;=StartupProcess，所以走的是&lt;code&gt;StartupProcessMain&lt;/code&gt;流程，这不同于&lt;strong&gt;walsender&lt;/strong&gt;,walwrite,bgwriter这些子进程的流程。startup进程本身是为了宕机恢复读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;switch&lt;/span&gt; (MyAuxProcType)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; CheckerProcess:
&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 set signals, they&amp;#39;re useless here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;CheckerModeMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; BootstrapProcess:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;			 * There was a brief instant during which mode was Normal; this 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;			 * okay. We need to be in bootstrap mode during BootStrapXLOG 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;			 * the sake of multixact initialization.
&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;SetProcessingMode&lt;/span&gt;(BootstrapProcessing);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;bootstrap_signals&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;BootStrapXLOG&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;BootstrapModeMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; StartupProcess: &lt;span style="color:#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;/* don&amp;#39;t set signals, startup process has its own agenda */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;StartupProcessMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; BgWriterProcess:
&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 set signals, bgwriter has its own agenda */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;BackgroundWriterMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; CheckpointerProcess:
&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 set signals, checkpointer has its own agenda */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;CheckpointerMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; WalWriterProcess:
&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 set signals, walwriter has its own agenda */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;InitXLOGAccess&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;WalWriterMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;case&lt;/span&gt; WalReceiverProcess:
&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 set signals, walreceiver has its own agenda */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;WalReceiverMain&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* should never 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:#66d9ef"&gt;default&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;elog&lt;/span&gt;(PANIC, &lt;span style="color:#e6db74"&gt;&amp;#34;unrecognized process type: %d&amp;#34;&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;) MyAuxProcType);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;proc_exit&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;7：&lt;code&gt;StartupProcessMain&lt;/code&gt;：主要是为了调用&lt;code&gt;StartupXLOG()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;6：&lt;code&gt;StartupXLOG&lt;/code&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;This must be called ONCE during postmaster or standalone&lt;span style="color:#f92672"&gt;-&lt;/span&gt;backend startup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;StartupXLOG&lt;/code&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; (ControlFile&lt;span style="color:#f92672"&gt;-&amp;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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; DB_IN_PRODUCTION:
&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;(LOG,
&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 system was interrupted; last known up at %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:#a6e22e"&gt;str_time&lt;/span&gt;(ControlFile&lt;span style="color:#f92672"&gt;-&amp;gt;&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;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;这跟log日志能对上，以下是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;2024-12-06 17:02:57.534 CST,,,447560,,65693cde.6d448,1325,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;database system is shut down&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.536 CST,,,211844,,6752bdf3.33b84,1,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;ending log output to stderr&amp;#34;&lt;/span&gt;,,&lt;span style="color:#e6db74"&gt;&amp;#34;Future log output will go to log destination &amp;#34;&amp;#34;csvlog&amp;#34;&amp;#34;.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.536 CST,,,211844,,6752bdf3.33b84,2,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;starting PostgreSQL 13.2 (RaseSQL 1.3) on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39.0.1), 64-bit&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.537 CST,,,211844,,6752bdf3.33b84,3,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;listening on IPv4 address &amp;#34;&amp;#34;0.0.0.0&amp;#34;&amp;#34;, port 7284&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.539 CST,,,211844,,6752bdf3.33b84,4,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;listening on Unix socket &amp;#34;&amp;#34;/tmp/.s.PGSQL.7284&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.557 CST,,,211995,,6752bdf5.33c1b,1,,2024-12-06 17:03:49 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;database system was interrupted; last known up at 2024-12-06 17:00:10 CST&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;startup&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;code&gt;in production&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;Database cluster state: in production&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;in production&lt;/code&gt;这个状态是&lt;strong&gt;数据库正在运行&lt;/strong&gt;，而不是正常的shutdown状态，说明当时数据库停库时&lt;strong&gt;不是一致性停库&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;继续其中关于fsync的关键代码：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;	 * If we previously crashed, perform a couple of actions:
&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 pg_wal directory may still include some temporary WAL segments
&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 when creating a new segment, so perform some clean up to 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;	 * bloat this path. This is done first as there is no point to sync
&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 temporary data.
&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;	 * - There might be data which we had written, intending to fsync it, but
&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 we had not actually fsync&amp;#39;d yet. Therefore, a power failure 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;	 * the near future might cause earlier unflushed writes to be lost, even
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * though more recent data written to disk from here on would be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * persisted. To avoid that, fsync the entire data 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:#66d9ef"&gt;if&lt;/span&gt; (ControlFile&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; DB_SHUTDOWNED &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;		ControlFile&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; DB_SHUTDOWNED_IN_RECOVERY)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;RemoveTempXlogFiles&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SyncDataDirectory&lt;/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;这里因为控制文件记录的状态不是正常停库的，所以走到if中调用&lt;code&gt;SyncDataDirectory()&lt;/code&gt;做fsync持久化。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;StartupXLOG&lt;/code&gt;做了很多很多事，其中跟spill相关的除了&lt;code&gt;SyncDataDirectory()&lt;/code&gt;还有&lt;code&gt;StartupReorderBuffer()&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;	 * Initialize replication slots, before there&amp;#39;s a chance to remove
&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 resources.
&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;StartupReplicationSlots&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Startup logical state, needs to be setup now so we have proper data
&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 crash recovery.
&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;StartupReorderBuffer&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;StartupReorderBuffer&lt;/code&gt;虽然也会被调用，它会调用&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;清理所有slot目录的spill文件（不是删除目录和state文件）&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Delete all data spilled to disk after we&amp;#39;ve restarted/crashed. It will be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * recreated when the respective slots are reused.
&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;StartupReorderBuffer&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;	DIR		 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logical_dir;
&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; dirent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logical_de;
&lt;/span&gt;&lt;/span&gt;&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_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AllocateDir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot&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;while&lt;/span&gt; ((logical_de &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReadDir&lt;/span&gt;(logical_dir, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot&amp;#34;&lt;/span&gt;)) &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; (&lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, &lt;span style="color:#e6db74"&gt;&amp;#34;.&amp;#34;&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, &lt;span style="color:#e6db74"&gt;&amp;#34;..&amp;#34;&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:#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:#75715e"&gt;/* if it cannot be a slot, skip the directory */&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;ReplicationSlotValidateName&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, DEBUG2))
&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:#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, has to be a surviving logical slot, iterate and 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;		 * everything starting with 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:#a6e22e"&gt;ReorderBufferCleanupSerializedTXNs&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_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 style="color:#a6e22e"&gt;FreeDir&lt;/span&gt;(logical_dir);
&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;5：&lt;code&gt;SyncDataDirectory&lt;/code&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-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; * Issue fsync recursively on PGDATA and all its contents.
&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 fsync regular files and directories wherever they are, but 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; * follow symlinks only for pg_wal and immediately under pg_tblspc.
&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 symlinks are presumed to point at files we&amp;#39;re not responsible
&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 fsyncing, and might not have privileges to write at all.
&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; * Errors are logged but not considered fatal; that&amp;#39;s because this is used
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * only during database startup, to deal with the possibility that there are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * issued-but-unsynced writes pending against the data directory. We want 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; * ensure that such writes reach disk before anything that&amp;#39;s done in the new
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * run. However, aborting on error would result in failure to start 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; * harmless cases such as read-only files in the data directory, and that&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; * not good either.
&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 that if we previously crashed due to a PANIC on fsync(), we&amp;#39;ll be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * rewriting all changes again during recovery.
&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 we assume we&amp;#39;re chdir&amp;#39;d into PGDATA to begin 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; */&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;strong&gt;fsync所有data目录文件使之持久化&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;这个动作只会发生在起库阶段&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;这个动作是为了保证在数据库运行前data目录是完全持久化的&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;SyncDataDirectory&lt;/code&gt;主体是递归遍历目录并fsync（link文件稍微特殊处理一下）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;walkdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;, datadir_fsync_fname, false, LOG);
&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; (xlog_is_symlink)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;walkdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_wal&amp;#34;&lt;/span&gt;, datadir_fsync_fname, false, LOG);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;walkdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_tblspc&amp;#34;&lt;/span&gt;, datadir_fsync_fname, true, LOG);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;4：&lt;code&gt;walkdir&lt;/code&gt;：递归到&lt;code&gt;.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;3：&lt;code&gt;walkdir&lt;/code&gt;：递归到&lt;code&gt;./pg_replslot&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;2：&lt;code&gt;walkdir&lt;/code&gt;：递归到&lt;code&gt;./pg_replslot/slotname&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;1：&lt;code&gt;lstat&lt;/code&gt; ：C库调用。&lt;code&gt;walkdir&lt;/code&gt;不仅要做fsync（入参函数&lt;code&gt;datadir_fsync_fname&lt;/code&gt;），&lt;code&gt;walkdir&lt;/code&gt;函数本体还要做 &lt;code&gt;lstat&lt;/code&gt;获取文件信息，如inode、文件大小、最近修改时间等等，类似linux的&lt;code&gt;stat&lt;/code&gt;命令。&lt;/p&gt;
&lt;p&gt;0：&lt;code&gt;_lxstat&lt;/code&gt;：C库调用&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;起库逻辑汇总&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg会启动一个辅助进程&lt;code&gt;startup&lt;/code&gt;以协助起库，不同于在常见的childprocess（walwriter、bgwriter、checkpointer等等）进程，它是起库过程中必定会启动的进程，它会做很多事情&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StartupXLOG&lt;/code&gt;起库时一定会被调用，无论数据库是否一致性停库&lt;/li&gt;
&lt;li&gt;只有非正常停库状态下，才会触发&lt;code&gt;SyncDataDirectory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SyncDataDirectory&lt;/code&gt;会fsync持久化所有data文件，并查看所有data文件的stat信息&lt;/li&gt;
&lt;li&gt;fsync是为了在库启动前保证data文件都一致；stat应该是为了验证文件是否正常和可读（在startup进程启动前只验证过datadir目录可读性）&lt;/li&gt;
&lt;li&gt;无论停库状态，&lt;code&gt;StartupReorderBuffer&lt;/code&gt;一定会被调用并清理所有复制槽的spill文件&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;什么时候是ready状态
 &lt;div id="什么时候是ready状态" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e6%98%afready%e7%8a%b6%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;startup进程把活干完后数据库还不是ready状态，在pmState状态机改变状态时会调用&lt;code&gt;reaper&lt;/code&gt;回收进程函数。reaper函数本身是为了子进程退出后进行一些回收或者启动工作。pmState状态机记录状态为PM_STARTUP，状态机是控制启停库状态的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PostmasterMain&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;	StartupPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartupDataBase&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;(StartupPID &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;	StartupStatus &lt;span style="color:#f92672"&gt;=&lt;/span&gt; STARTUP_RUNNING;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_STARTUP; &lt;span 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;/* Some workers may be scheduled to start now */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;maybe_start_bgworkers&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerLoop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * ServerLoop probably shouldn&amp;#39;t ever return, but if it does, close down.
&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;ExitPostmaster&lt;/span&gt;(status &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; STATUS_OK);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;abort&lt;/span&gt;();					&lt;span style="color:#75715e"&gt;/* not reached */&lt;/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;PostmasterMain&lt;/code&gt;起库的核心流程会走到&lt;code&gt;reaper&lt;/code&gt;以处理startup进程的正常退出，&lt;/p&gt;
&lt;p&gt;PMState注释：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * We use a simple state machine to control startup, shutdown, 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; * crash recovery (which is rather like shutdown followed by startup).
&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; * After doing all the postmaster initialization work, we enter PM_STARTUP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * state and the startup process is launched. The startup process begins by
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * reading the control file and other preliminary initialization steps.
&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 a normal startup, or after crash recovery, the startup process exits
&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 exit code 0 and we switch to PM_RUN state. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;PMState会被信号传递和处理，startup进程退出后&lt;code&gt;reaper&lt;/code&gt;会被激活以回收进程。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reaper&lt;/code&gt;函数处理startup子进程的正常退出态：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; (pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; StartupPID)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			StartupPID &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;			&lt;span style="color:#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;			 * Startup succeeded, commence normal operations
&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;			StartupStatus &lt;span style="color:#f92672"&gt;=&lt;/span&gt; STARTUP_NOT_RUNNING; &lt;span style="color:#75715e"&gt;//由STARTUP_RUNNING转成STARTUP_NOT_RUNNING
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			FatalError &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false; &lt;span style="color:#75715e"&gt;//上面一堆if未命中后，才不是fatal的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			AbortStartTime &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;			ReachedNormalRunning &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;			pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_RUN; &lt;span style="color:#75715e"&gt;//状态机由PM_STARTUP转成PM_RUN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			connsAllowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ALLOW_ALL_CONNS;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;			 * Crank up the background tasks, if we didn&amp;#39;t do that 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;			 * when we entered consistent recovery state. It doesn&amp;#39;t matter
&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 this fails, we&amp;#39;ll just try again later.
&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; (CheckpointerPID &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;				CheckpointerPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartCheckpointer&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; (BgWriterPID &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;				BgWriterPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartBackgroundWriter&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; (WalWriterPID &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;				WalWriterPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartWalWriter&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;			 * Likewise, start other special children as needed. In a restart
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * situation, some of them may be alive 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;			 */&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;IsBinaryUpgrade &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AutoVacuumingActive&lt;/span&gt;() &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; AutoVacPID &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;				AutoVacPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartAutoVacLauncher&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;PgArchStartupAllowed&lt;/span&gt;() &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; PgArchPID &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;				PgArchPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pgarch_start&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; (PgStatPID &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;				PgStatPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pgstat_start&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* workers may be scheduled to start now */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;maybe_start_bgworkers&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 this point we are really open for business */&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;(LOG,
&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 system is ready to accept connections&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;/* Report status */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;AddToDataDirLockFile&lt;/span&gt;(LOCK_FILE_LINE_PM_STATUS, PM_STATUS_READY);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifdef USE_SYSTEMD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;sd_notify&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;READY=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:#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;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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;“database system is ready to accept connections”信息就在这里了&lt;/p&gt;
&lt;p&gt;checkpointer、bgwrite、walwrite、autovacuum、arch（如有）、stat这些进程都需要启动，在这个阶段拉起这些进程不是必须返回成功的，后续也可以在&lt;code&gt;ServerLoop&lt;/code&gt;或者再次执行&lt;code&gt;reaper&lt;/code&gt;时尝试启动，只有startup进程是必须一次性必须启动并完成所有相关任务的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; (pid &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;/* in parent, fork failed */&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;			save_errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; errno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; save_errno;
&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; (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; StartupProcess:
&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;(LOG,
&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;could not fork startup process: %m&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;break&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; BgWriterProcess:
&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;(LOG,
&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;could not fork background writer process: %m&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;break&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; CheckpointerProcess:
&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;(LOG,
&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;could not fork checkpointer process: %m&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;break&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; WalWriterProcess:
&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;(LOG,
&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;could not fork WAL writer process: %m&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;break&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; WalReceiverProcess:
&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;(LOG,
&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;could not fork WAL receiver process: %m&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;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;ereport&lt;/span&gt;(LOG,
&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;could not fork process: %m&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;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 style="color:#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;		 * fork failure is fatal during startup, but there&amp;#39;s no need to choke
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * immediately if starting other child types fails.
&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; (type &lt;span style="color:#f92672"&gt;==&lt;/span&gt; StartupProcess)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ExitPostmaster&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;return&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;h2 class="relative group"&gt;spill文件生成逻辑各版本差异
 &lt;div id="spill文件生成逻辑各版本差异" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#spill%e6%96%87%e4%bb%b6%e7%94%9f%e6%88%90%e9%80%bb%e8%be%91%e5%90%84%e7%89%88%e6%9c%ac%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;spill在各个版本都是spill最大的事务，这里重点关注啥时候spill的逻辑&lt;/p&gt;
&lt;p&gt;PG12：pg12的changes是4096条写死&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;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&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;/*
&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 the transaction tx should spill its data 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;ReorderBufferCheckSerializeTXN&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;	&lt;span style="color:#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;	 * TODO: improve accounting so we cheaply can take subtransactions into
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * account 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; (txn&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nentries_mem &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; max_changes_in_memory)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ReorderBufferSerializeTXN&lt;/span&gt;(rb, txn);
&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;(txn&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nentries_mem &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;PG13:超过&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;内存大小就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:#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;ReorderBufferCheckMemoryLimit&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;while&lt;/span&gt; (rb&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;size &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; logical_decoding_work_mem &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1024L&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * Pick the largest transaction (or subtransaction) and evict it from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * memory by serializing it 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;		txn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReorderBufferLargestTXN&lt;/span&gt;(rb);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ReorderBufferSerializeTXN&lt;/span&gt;(rb, 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;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;PG14：多个了一个流式传输ReorderBufferStreamTXN&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;ReorderBufferCheckMemoryLimit&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;while&lt;/span&gt; (rb&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;size &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; logical_decoding_work_mem &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1024L&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * Pick the largest transaction (or subtransaction) and evict it from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * memory by streaming, if possible. Otherwise, spill 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;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;ReorderBufferCanStartStreaming&lt;/span&gt;(rb) &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;			(txn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReorderBufferLargestTopTXN&lt;/span&gt;(rb)) &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;ReorderBufferStreamTXN&lt;/span&gt;(rb, 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;		&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;ReorderBufferSerializeTXN&lt;/span&gt;(rb, 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;...
&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;14虽然有了流式复制，但是触发是要一定条件的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;/* Returns true, if the streaming can be started now, false, otherwise. */&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;inline&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;ReorderBufferCanStartStreaming&lt;/span&gt;(ReorderBuffer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rb)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	LogicalDecodingContext &lt;span style="color:#f92672"&gt;*&lt;/span&gt;ctx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rb&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;private_data;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SnapBuild &lt;span style="color:#f92672"&gt;*&lt;/span&gt;builder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ctx&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;snapshot_builder;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 can&amp;#39;t start streaming unless a consistent state is reached. */&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;SnapBuildCurrentState&lt;/span&gt;(builder) &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:#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;/*
&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 can&amp;#39;t start streaming immediately even if the streaming is enabled
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * because we previously decoded this transaction and now just are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * restarting.
&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;ReorderBufferCanStream&lt;/span&gt;(rb) &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;SnapBuildXactNeedsSkip&lt;/span&gt;(builder, ctx&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;reader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;EndRecPtr))
&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:#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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;	 * Found a point after SNAPBUILD_FULL_SNAPSHOT where all transactions 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;	 * were running at that point finished. Till we reach that we hold off
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * calling any commit callbacks.
&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;	SNAPBUILD_CONSISTENT &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;额外的steam触发条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;条件1：快照中的事务涵盖的所有事务都已完成（应该指commit or rollback）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;条件2：context是私有数据（是不是说两条链路一张表就不会触发steam？）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;条件3：快照中的事务是不可忽略的事务（可能指特殊的事务可以忽略，就不做了）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG15：跟14差不多，只是函数更清晰，套娃少一些了&lt;/p&gt;
&lt;p&gt;PG16：差不多&lt;/p&gt;
&lt;p&gt;PG17：差不多，新增一个&lt;code&gt;DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE&lt;/code&gt;可以强制stream&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;记忆点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PG12及以前是写死的4096条changes&lt;/li&gt;
&lt;li&gt;PG13新增&lt;code&gt;logical_decoding_work_mem&lt;/code&gt;参数，可调整内存大小以减少spill概率&lt;/li&gt;
&lt;li&gt;PG14及以后支持流式复制Streaming&lt;/li&gt;
&lt;li&gt;触发流式复制也需要一定的条件，所以即使有流式复制也可能会发生spill&lt;/li&gt;
&lt;li&gt;PG17新增&lt;code&gt;debug_logical_replication_streaming&lt;/code&gt;参数以强制触发流式传输&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;spill文件清理逻辑
 &lt;div id="spill文件清理逻辑" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#spill%e6%96%87%e4%bb%b6%e6%b8%85%e7%90%86%e9%80%bb%e8%be%91" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;起库时清理spill其实只是一种场景，还有启动walsender清理和drop slot清理。&lt;/p&gt;

&lt;h3 class="relative group"&gt;walsender启动时清理
 &lt;div id="walsender启动时清理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#walsender%e5%90%af%e5%8a%a8%e6%97%b6%e6%b8%85%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;会在数据库启动（walsender还没有启动）、walsender启动（数据库运行中）时被调用，注意这两部分场景是不一样的，只是他们会调用同一个函数。从函数注释部分也可以看出，该函数是为了“删除残留的序列化的reorder buffers”，即清理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; * Remove any leftover serialized reorder buffers from a slot directory 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; * prior crash or decoding session exit.
&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;ReorderBufferCleanupSerializedTXNs&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;slotname)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	DIR		 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;spill_dir;
&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; dirent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;spill_de;
&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; stat statbuf;
&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;		path[MAXPGPATH &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;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 style="color:#a6e22e"&gt;sprintf&lt;/span&gt;(path, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot/%s&amp;#34;&lt;/span&gt;, slotname);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 only handling directories here, skip if it&amp;#39;s not ours */&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;lstat&lt;/span&gt;(path, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;statbuf) &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 style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;S_ISDIR&lt;/span&gt;(statbuf.st_mode))
&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;	spill_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AllocateDir&lt;/span&gt;(path);
&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; ((spill_de &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReadDirExtended&lt;/span&gt;(spill_dir, path, INFO)) &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;/* only look at names that can be ours */&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个字符
&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;strncmp&lt;/span&gt;(spill_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, &lt;span style="color:#e6db74"&gt;&amp;#34;xid&amp;#34;&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;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(path),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot/%s/%s&amp;#34;&lt;/span&gt;, slotname,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 spill_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_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 style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;unlink&lt;/span&gt;(path) &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:#a6e22e"&gt;ereport&lt;/span&gt;(ERROR,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						(&lt;span style="color:#a6e22e"&gt;errcode_for_file_access&lt;/span&gt;(),mkdir 
&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;could not remove file &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; during removal of pg_replslot/%s/xid*: %m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								path, slotname)));
&lt;/span&gt;&lt;/span&gt;&lt;span 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;FreeDir&lt;/span&gt;(spill_dir);
&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;清理文件名以“xid”开头的文件。很明显state文件是不能清理的&lt;/li&gt;
&lt;li&gt;unlink清理，一次清理一个文件。考虑这一点可以帮助我们构建加速起库方案&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%95%b0%e6%8d%ae%e5%ba%93%e5%90%af%e5%8a%a8%e6%97%b6%e6%b8%85%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;数据库启动时会fork一个startup进程来清理slot，清理函数跟walsender调用的清理函数一致：&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;还有一个区别在于，walsender重启后，只会清理当前同名slot spill；而数据库启动时会顺序清理所有slot spill。&lt;/p&gt;
&lt;p&gt;数据库启动startup进程，while顺序清理逻辑：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;StartupReorderBuffer&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;	DIR		 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logical_dir;
&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; dirent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;logical_de;
&lt;/span&gt;&lt;/span&gt;&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_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AllocateDir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot&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;while&lt;/span&gt; ((logical_de &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReadDir&lt;/span&gt;(logical_dir, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot&amp;#34;&lt;/span&gt;)) &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;strcmp&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, &lt;span style="color:#e6db74"&gt;&amp;#34;.&amp;#34;&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;strcmp&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, &lt;span style="color:#e6db74"&gt;&amp;#34;..&amp;#34;&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:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//验证slotname是否规范
&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 it cannot be a slot, skip the directory */&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;ReplicationSlotValidateName&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_name, DEBUG2))
&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:#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, has to be a surviving logical slot, iterate and 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;		 * everything starting with 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:#a6e22e"&gt;ReorderBufferCleanupSerializedTXNs&lt;/span&gt;(logical_de&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;d_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 style="color:#a6e22e"&gt;FreeDir&lt;/span&gt;(logical_dir);
&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;while循环调用&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;，后面跟walsender启动清理逻辑就一样了。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg_drop_replication_slot手动清理
 &lt;div id="pg_drop_replication_slot手动清理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_drop_replication_slot%e6%89%8b%e5%8a%a8%e6%b8%85%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;drop slot清理逻辑跟自动清理spill文件的逻辑&lt;strong&gt;不一样&lt;/strong&gt;，它没有调用到&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;drop slot流程如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg_drop_replication_slot(PG_FUNCTION_ARGS)&lt;/code&gt;-&amp;gt;&lt;code&gt;ReplicationSlotDrop(const char *name, bool nowait)&lt;/code&gt;-&amp;gt;&lt;code&gt;ReplicationSlotDropAcquired(void)&lt;/code&gt;-&amp;gt;&lt;code&gt;ReplicationSlotDropPtr&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ReplicationSlotDropPtr&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; * Permanently drop the replication slot which will be released by the point
&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 function returns.
&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;ReplicationSlotDropPtr&lt;/span&gt;(ReplicationSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;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:#66d9ef"&gt;char&lt;/span&gt;		path[MAXPGPATH];
&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;		tmppath[MAXPGPATH];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 some other backend ran this code concurrently with us, we might try
&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 delete a slot with a certain name while someone else was trying 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;	 * create a slot with the same name.
&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;LWLockAcquire&lt;/span&gt;(ReplicationSlotAllocationLock, 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;/* Generate pathnames. */&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_replslot/%s&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;NameStr&lt;/span&gt;(slot&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;	&lt;span style="color:#a6e22e"&gt;sprintf&lt;/span&gt;(tmppath, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot/%s.tmp&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;NameStr&lt;/span&gt;(slot&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#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;	 * Rename the slot directory on disk, so that we&amp;#39;ll no longer recognize
&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 as a valid slot. Note that if this fails, we&amp;#39;ve got to mark 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;	 * slot inactive before bailing out. If we&amp;#39;re dropping an ephemeral or 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;	 * temporary slot, we better never fail hard as the caller won&amp;#39;t expect
&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 slot to survive and this might get called during error handling.
&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;rename&lt;/span&gt;(path, tmppath) &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;//rename文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 need to fsync() the directory we just renamed and its parent 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;		 * make sure that our changes are on disk in a crash-safe fashion. 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;		 * fsync() fails, we can&amp;#39;t be sure whether the changes are on disk 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;		 * not. For now, we handle that by panicking;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * StartupReplicationSlots() will try to straighten it out 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;		 * restart.
&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;//fsync持久化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;START_CRIT_SECTION&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;(tmppath, true);
&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_replslot&amp;#34;&lt;/span&gt;, true);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;END_CRIT_SECTION&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#75715e"&gt;	 * If removing the directory fails, the worst thing that will happen 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;	 * that the user won&amp;#39;t be able to create a new slot with the same name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * until the next server restart. We warn about it, but that&amp;#39;s all.
&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;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rmtree&lt;/span&gt;(tmppath, true))
&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;could not remove directory &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;&amp;#34;&lt;/span&gt;, tmppath)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#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 release this at the very end, so that nobody starts trying to create
&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 slot while we&amp;#39;re still cleaning up the detritus of the old one.
&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;LWLockRelease&lt;/span&gt;(ReplicationSlotAllocationLock);
&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;drop slot不是直接去复制槽目录下面去unlink，而是先把复制槽目录&lt;code&gt;slotname/&lt;/code&gt;rename成 &lt;code&gt;slotname.tmp/&lt;/code&gt;，然后再去做unlink目录下的文件，最后再删除 &lt;code&gt;slotname.tmp/&lt;/code&gt;目录本身。&lt;/p&gt;
&lt;p&gt;其中rmtree也是在循环unlink文件。&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%a4%8d%e5%88%b6%e6%a7%bd%e6%ba%a2%e5%87%ba%e5%8f%91%e7%94%9f%e5%90%8e%e5%8a%a0%e9%80%9f%e8%b5%b7%e5%ba%93%e6%96%b9%e6%a1%88%e6%b5%8b%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;1000w个spill删除起来肯定是很慢的，直接mv目录的话就非常快。但是直接mv需要注意mv后的名称和state文件，以及需要知道mv到底跳过了哪一个源码步骤。&lt;/p&gt;

&lt;h3 class="relative group"&gt;mv的名称注意事项
 &lt;div id="mv的名称注意事项" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mv%e7%9a%84%e5%90%8d%e7%a7%b0%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于是异常停库，startup进程会执行&lt;code&gt;SyncDataDirectory&lt;/code&gt;fsync和stat所有data文件，这一点是比较难绕过的。&lt;code&gt;SyncDataDirectory&lt;/code&gt;做完以后，才开始处理复制槽。处理复制槽时会调用&lt;code&gt;StartupReorderBuffer()&lt;/code&gt;-&amp;gt;&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;全量清理spill文件。&lt;/p&gt;
&lt;p&gt;在进入清理前，会调用&lt;code&gt;ReplicationSlotValidateName&lt;/code&gt;校验复制槽名称的有效性，我们可以在&lt;code&gt;ReplicationSlotValidateName&lt;/code&gt;上做文章，以骗过startup进程跳过&lt;code&gt;ReorderBufferCleanupSerializedTXNs&lt;/code&gt;的过程。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ReplicationSlotValidateName&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;ReplicationSlotValidateName&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;int&lt;/span&gt; elevel)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;for&lt;/span&gt; (cp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; name; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp; cp&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;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;((&lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp &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; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp &lt;span style="color:#f92672"&gt;&amp;lt;=&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:#f92672"&gt;||&lt;/span&gt; (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;9&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;||&lt;/span&gt; (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;cp &lt;span style="color:#f92672"&gt;==&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;			&lt;span style="color:#a6e22e"&gt;ereport&lt;/span&gt;(elevel,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					(&lt;span style="color:#a6e22e"&gt;errcode&lt;/span&gt;(ERRCODE_INVALID_NAME),
&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;replication slot name &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; contains invalid character&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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Replication slot names may only contain lower case letters, numbers, and the underscore character.&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;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:#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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有效slot name只包含&lt;code&gt;a-z&lt;/code&gt;;&lt;code&gt;0-9&lt;/code&gt;;&lt;code&gt;_&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以rename时建议加个点&lt;code&gt;.&lt;/code&gt;，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;建议&lt;/em&gt;&lt;code&gt;slotname.bak&lt;/code&gt;,&lt;code&gt;slotname.20241215&lt;/code&gt;等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;不建议&lt;/em&gt;&lt;code&gt;slotnamebackup&lt;/code&gt;,&lt;code&gt;slotname20241215&lt;/code&gt;,&lt;code&gt;slotname_bak&lt;/code&gt;等等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;不建议&lt;/em&gt;&lt;code&gt;.tmp&lt;/code&gt;后缀，slotname有&lt;code&gt;.tmp&lt;/code&gt;后缀有特殊含义&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后rename后，要创建目录和拷贝state，不然启动的slot会表现的很反常（比如重复的slotname、自动生产一个slotname、删不到slot、下游起不来链路等等）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;汇总推荐mv操作如下：&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;cd pg_replslot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv slotname slotname.bak 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir slotname
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp slotname.bak/state slotname/&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="#%e8%b5%b7%e5%ba%93%e6%97%b6%e9%97%b4%e5%af%b9%e6%af%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;对比不同源码流程起库速度，看看手工mv/rm加速起库到底有没有意义。&lt;/p&gt;
&lt;p&gt;参考源码逻辑原理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正常停库，走fsync和stat&lt;/li&gt;
&lt;li&gt;异常停库，走fsync和stat；&lt;/li&gt;
&lt;li&gt;有效mv，将slotname目录命名为&lt;code&gt;.bak&lt;/code&gt;，不走unlink&lt;/li&gt;
&lt;li&gt;无效mv，将slotname目录命名为&lt;code&gt;_bak&lt;/code&gt;且spill文件命名为xid开头，走unlink&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于正常spill文件实在太慢，这里手工伪造slot目录和spill文件，总共50个slot，每个slot 40w个spill，总共2000w个spill来测试起库时间（用cp目录的方式要比cp文件、dd文件快很多）。&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;1&lt;/td&gt;
 &lt;td&gt;正常停库；起库不做fsync和stat，不做unlink&lt;/td&gt;
 &lt;td&gt;0.1秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;正常停库，无效mv；起库不做fsync和stat，做unlink&lt;/td&gt;
 &lt;td&gt;11分41秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;异常停库，有效mv；起库做fsync和stat，不做unlink&lt;/td&gt;
 &lt;td&gt;4分35秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;异常停库，无效mv；起库做fsync和stat，做unlink&lt;/td&gt;
 &lt;td&gt;32分2秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;异常停库，rm（创建slot目录并保留state）&lt;/td&gt;
 &lt;td&gt;13分04秒&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对比方案3、5，理论上当时的场景我们有效mv可以做到4分钟左右起库，rm的话13分钟左右。（这是一个粗糙的对比，恢复环境已经观察到有些东西不一样了）&lt;/p&gt;</content:encoded></item><item><title>PG停库逻辑和walsender阻止停库问题分析</title><link>https://lastdba.com/2025/01/04/pg%E5%81%9C%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cwalsender%E9%98%BB%E6%AD%A2%E5%81%9C%E5%BA%93%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/</link><pubDate>Sat, 04 Jan 2025 00:00:00 +0000</pubDate><guid>https://lastdba.com/2025/01/04/pg%E5%81%9C%E5%BA%93%E9%80%BB%E8%BE%91%E5%92%8Cwalsender%E9%98%BB%E6%AD%A2%E5%81%9C%E5%BA%93%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/</guid><description>&lt;h2 class="relative group"&gt;walsender阻止停库现象
 &lt;div id="walsender阻止停库现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#walsender%e9%98%bb%e6%ad%a2%e5%81%9c%e5%ba%93%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;2024-12-06 17:00:02.036 CST,,,447560,,65693cde.6d448,1320,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;received fast shutdown request&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:02.295 CST,,,447560,,65693cde.6d448,1322,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;background worker &amp;#34;&amp;#34;logical replication launcher&amp;#34;&amp;#34; (PID 448996) exited with exit code 1&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:10.627 CST,,,448990,,65693ce0.6d9de,213833,,2023-12-01 09:54:40 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpoint complete: wrote 426844 buffers (5.1%); 0 WAL file(s) added, 0 removed, 5 recycled; write=91.427 s, sync=0.055 s, total=91.508 s; sync files=761, longest=0.028 s, average=0.001 s; distance=2197531 kB, estimate=2680783 kB&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpointer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:10.628 CST,,,448990,,65693ce0.6d9de,213834,,2023-12-01 09:54:40 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;shutting down&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpointer&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;--checkpointer做完checkpoint，并处于shutting down状态，pm没有退出
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--160s后pm接收到immediate shutdown，由探活脚本触发
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.348 CST,,,447560,,65693cde.6d448,1323,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;received immediate shutdown request&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,283840,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:39865&amp;#34;&lt;/span&gt;,6751a2dc.454c0,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-12-05 20:55:56 CST,89/847309655,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157641,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:39407&amp;#34;&lt;/span&gt;,67408354.267c9,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:52 CST,9/3193590104,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157916,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:57038&amp;#34;&lt;/span&gt;,67408356.268dc,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:54 CST,115/3293293502,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,164392,&lt;span style="color:#e6db74"&gt;&amp;#34;30.151.40.19:41641&amp;#34;&lt;/span&gt;,66b25869.28228,3,&lt;span style="color:#e6db74"&gt;&amp;#34;streaming 42D3B/1732C5F0&amp;#34;&lt;/span&gt;,2024-08-07 01:07:53 CST,296/0,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;standby_6666&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.371 CST,,,447560,,65693cde.6d448,1324,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;archiver process (PID 448994) exited with exit code 2&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.371 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,57755,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:38918&amp;#34;&lt;/span&gt;,67125534.e19b,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-10-18 20:31:48 CST,243/902018192,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.372 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157915,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:43433&amp;#34;&lt;/span&gt;,67408356.268db,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:54 CST,60/3248014863,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--pm停完
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:57.534 CST,,,447560,,65693cde.6d448,1325,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;database system is shut down&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.536 CST,,,211844,,6752bdf3.33b84,1,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;ending log output to stderr&amp;#34;&lt;/span&gt;,,&lt;span style="color:#e6db74"&gt;&amp;#34;Future log output will go to log destination &amp;#34;&amp;#34;csvlog&amp;#34;&amp;#34;.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&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;17:00:02 postmaster接到fast停库&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;walsender阻止停库现象
 &lt;div id="walsender阻止停库现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#walsender%e9%98%bb%e6%ad%a2%e5%81%9c%e5%ba%93%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;2024-12-06 17:00:02.036 CST,,,447560,,65693cde.6d448,1320,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;received fast shutdown request&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:02.295 CST,,,447560,,65693cde.6d448,1322,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;background worker &amp;#34;&amp;#34;logical replication launcher&amp;#34;&amp;#34; (PID 448996) exited with exit code 1&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:10.627 CST,,,448990,,65693ce0.6d9de,213833,,2023-12-01 09:54:40 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpoint complete: wrote 426844 buffers (5.1%); 0 WAL file(s) added, 0 removed, 5 recycled; write=91.427 s, sync=0.055 s, total=91.508 s; sync files=761, longest=0.028 s, average=0.001 s; distance=2197531 kB, estimate=2680783 kB&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpointer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:00:10.628 CST,,,448990,,65693ce0.6d9de,213834,,2023-12-01 09:54:40 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;shutting down&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpointer&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;--checkpointer做完checkpoint，并处于shutting down状态，pm没有退出
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--160s后pm接收到immediate shutdown，由探活脚本触发
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.348 CST,,,447560,,65693cde.6d448,1323,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;received immediate shutdown request&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,283840,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:39865&amp;#34;&lt;/span&gt;,6751a2dc.454c0,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-12-05 20:55:56 CST,89/847309655,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157641,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:39407&amp;#34;&lt;/span&gt;,67408354.267c9,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:52 CST,9/3193590104,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157916,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:57038&amp;#34;&lt;/span&gt;,67408356.268dc,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:54 CST,115/3293293502,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.370 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,164392,&lt;span style="color:#e6db74"&gt;&amp;#34;30.151.40.19:41641&amp;#34;&lt;/span&gt;,66b25869.28228,3,&lt;span style="color:#e6db74"&gt;&amp;#34;streaming 42D3B/1732C5F0&amp;#34;&lt;/span&gt;,2024-08-07 01:07:53 CST,296/0,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;standby_6666&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.371 CST,,,447560,,65693cde.6d448,1324,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;archiver process (PID 448994) exited with exit code 2&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.371 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,57755,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:38918&amp;#34;&lt;/span&gt;,67125534.e19b,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-10-18 20:31:48 CST,243/902018192,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:43.372 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;logicaluser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,157915,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.77.159:43433&amp;#34;&lt;/span&gt;,67408356.268db,7,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-11-22 21:12:54 CST,60/3248014863,0,WARNING,57P02,&lt;span style="color:#e6db74"&gt;&amp;#34;terminating connection because of crash of another server process&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;In a moment you should be able to reconnect to the database and repeat your command.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;Debezium Streaming&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;walsender&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--pm停完
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:02:57.534 CST,,,447560,,65693cde.6d448,1325,,2023-12-01 09:54:38 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;database system is shut down&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-12-06 17:03:49.536 CST,,,211844,,6752bdf3.33b84,1,,2024-12-06 17:03:47 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;ending log output to stderr&amp;#34;&lt;/span&gt;,,&lt;span style="color:#e6db74"&gt;&amp;#34;Future log output will go to log destination &amp;#34;&amp;#34;csvlog&amp;#34;&amp;#34;.&amp;#34;&lt;/span&gt;,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&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;17:00:02 postmaster接到fast停库&lt;/p&gt;
&lt;p&gt;17:00:10 checkpoint做完，checkpointer停了&lt;/p&gt;
&lt;p&gt;17:02:43 postmaster接到immediate停库&lt;/p&gt;
&lt;p&gt;17:02:43 1个物理链路和5个逻辑链路walsender停了&lt;/p&gt;
&lt;p&gt;17:02:57 postmaster停了&lt;/p&gt;
&lt;p&gt;17:03:49 postmaster接到启动任务&lt;/p&gt;
&lt;p&gt;从以上信息可以看出，实际上还是walsender阻止了停库&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%81%9c%e5%ba%93%e5%92%8c%e4%bf%a1%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在撸源码前需要先了解信号和pg中的信号注册&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%b8%b8%e7%94%a8%e4%bf%a1%e5%8f%b7" 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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kill -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGHUP 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGINT 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGQUIT 4&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGILL 5&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGTRAP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGABRT 7&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGBUS 8&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGFPE 9&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGKILL 10&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGUSR1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGSEGV 12&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGUSR2 13&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGPIPE 14&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGALRM 15&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGTERM
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGSTKFLT 17&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGCHLD 18&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGCONT 19&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGSTOP 20&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGTSTP
&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常用的信号：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-1&lt;/code&gt; 或&lt;code&gt;-SIGHUP&lt;/code&gt;：挂起信号，在PG中通常是通知进程重新加载配置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-2&lt;/code&gt; 或&lt;code&gt;-SIGINT&lt;/code&gt;：中断信号（通常是&lt;code&gt;Ctrl+C&lt;/code&gt;），在pg中同城对应取消命令。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-3&lt;/code&gt;或&lt;code&gt;-SIGQUIT&lt;/code&gt;：pg中通常是强制退出die&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-9&lt;/code&gt; 或 &lt;code&gt;-SIGKILL&lt;/code&gt;：无条件终止信号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-15&lt;/code&gt;或 &lt;code&gt;-SIGTERM&lt;/code&gt;：终止信号，&lt;code&gt;pg_terminate_backend&lt;/code&gt;使用的信号，pg中通常是合理退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-10&lt;/code&gt;或&lt;code&gt;-SIGUSR1&lt;/code&gt;：自定义信号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-12&lt;/code&gt;或&lt;code&gt;-SIGUSR2&lt;/code&gt;：自定义信号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-17&lt;/code&gt;或&lt;code&gt;SIGCHLD&lt;/code&gt;：pm进程使用的信号，一般是子进程退出后pm接受该信号触发回收子进程任务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG中具体哪种类型的进程注册的信号含义，看各自进程源码基本都能找到。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg_ctl 定义的停库
 &lt;div id="pg_ctl-定义的停库" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_ctl-%e5%ae%9a%e4%b9%89%e7%9a%84%e5%81%9c%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;有几种方法可以关闭pg库。在底层，它们都归结为向postmaster进程发送一个信号。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;signal&lt;/th&gt;
 &lt;th&gt;pg_ctl&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;SIGTERM&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;Smart Shutdown&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;不允许新的连接，但允许现有会话正常结束其工作。只有在所有会话终止后，它才会关闭&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SIGINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;Fast Shutdown&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;服务器不允许新的连接，并向所有现有的子进程发送&lt;strong&gt;SIGTERM&lt;/strong&gt;，中止当前的事务并迅速退出。等待几乎所有子进程（有几个子进程不需要）退出，最后关闭&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SIGQUIT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;Immediate Shutdown&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;将向所有子进程发送&lt;strong&gt;SIGQUIT&lt;/strong&gt;，并等待它们终止。如果在5秒内有子进程没有终止，它们将被发送&lt;strong&gt;SIGKILL&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;注意，&lt;code&gt;pg_ctl&lt;/code&gt;没有发送&lt;code&gt;SIGKILL&lt;/code&gt;（&lt;code&gt;kill -9&lt;/code&gt;）的参数，但其实是可以直接对pm发送&lt;code&gt;SIGKILL&lt;/code&gt;的，但肯定不推荐这么做，&lt;code&gt;SIGKILL&lt;/code&gt; pm时pm不会对子进程、共享内存、信号量做任何处理。因为&lt;code&gt;SIGQUIT&lt;/code&gt; pm有兜底逻辑做子进程的&lt;code&gt;SIGKILL&lt;/code&gt;，所以&lt;code&gt;SIGQUIT&lt;/code&gt; pm基本能保证pm能停下来。&lt;/p&gt;
&lt;p&gt;在源码中，&lt;strong&gt;停库状态&lt;/strong&gt;总共只有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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* Startup/shutdown state */&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			NoShutdown		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			SmartShutdown	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			FastShutdown	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			ImmediateShutdown	3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这些状态会在停库routine源码中常见，一般通过变量&lt;code&gt;Shutdown&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;Shutdown &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; FastShutdown&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;pm信号
 &lt;div id="pm信号" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pm%e4%bf%a1%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&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-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;PostmasterMain&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; argc, &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;argv[])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;pqsignal_pm&lt;/span&gt;(SIGHUP, SIGHUP_handler);	&lt;span style="color:#75715e"&gt;/* reread config file and have
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;											 * children do same */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGINT, pmdie); &lt;span style="color:#75715e"&gt;/* send SIGTERM and shut down */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGQUIT, pmdie);	&lt;span style="color:#75715e"&gt;/* send SIGQUIT and die */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGTERM, pmdie);	&lt;span style="color:#75715e"&gt;/* wait for children and shut down */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGALRM, SIG_IGN);	&lt;span style="color:#75715e"&gt;/* ignored */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGPIPE, SIG_IGN);	&lt;span style="color:#75715e"&gt;/* ignored */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGUSR1, sigusr1_handler);	&lt;span style="color:#75715e"&gt;/* message from child process */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGUSR2, dummy_handler);	&lt;span style="color:#75715e"&gt;/* unused, reserve for children */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal_pm&lt;/span&gt;(SIGCHLD, reaper);	&lt;span style="color:#75715e"&gt;/* handle child termination */&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;pmdie&lt;/code&gt;：停库的三种信号会调用&lt;code&gt;pmdie&lt;/code&gt;函数，&lt;code&gt;pmdie&lt;/code&gt;是停库的关键函数，下面会重点分析。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reaper&lt;/code&gt;：停库时会处理子进程退出清理，所以在停库的逻辑中。子进程退出会给pm发生&lt;code&gt;SIGCHLD&lt;/code&gt;信号，然后进入&lt;code&gt;reaper&lt;/code&gt;清理子进程，每种子进程的清理也有自己的逻辑，比如checkpointer进程的正常退出会判断archiver和walsender是否完成了各自的任务。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sigusr1&lt;/code&gt;、&lt;code&gt;sigusr2&lt;/code&gt;：&lt;code&gt;sigusr1_handler&lt;/code&gt;是&lt;code&gt;SIGUSER1&lt;/code&gt;的标准routine，每种子进程对于&lt;code&gt;SIGUSR1&lt;/code&gt;的处理行为各不同；&lt;code&gt;SIGUSR2&lt;/code&gt;完全是子进程自定义行为了，有些子进程没有注册这个信号。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;walsender的信号
 &lt;div id="walsender的信号" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#walsender%e7%9a%84%e4%bf%a1%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;子进程fork出来时，首先就要注册信号。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WalSndSignals&lt;/code&gt;注册walsender进程的信号：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;/* Set up signal handlers */&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;WalSndSignals&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:#75715e"&gt;/* Set up signal handlers */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGHUP, SignalHandlerForConfigReload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGINT, StatementCancelHandler);	&lt;span style="color:#75715e"&gt;/* query cancel */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGTERM, die);		&lt;span style="color:#75715e"&gt;/* request shutdown */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGQUIT, quickdie);	&lt;span style="color:#75715e"&gt;/* hard crash time */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;InitializeTimeouts&lt;/span&gt;();		&lt;span style="color:#75715e"&gt;/* establishes SIGALRM handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGPIPE, SIG_IGN);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR1, procsignal_sigusr1_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR2, WalSndLastCycleHandler);	&lt;span style="color:#75715e"&gt;/* request a last cycle 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;												 * shutdown */&lt;/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;SIGUSR1&lt;/code&gt;和&lt;code&gt;SIGUSR2&lt;/code&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;checkpointer的信号
 &lt;div id="checkpointer的信号" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#checkpointer%e7%9a%84%e4%bf%a1%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CheckpointerMain&lt;/code&gt;注册checkpointer的信号：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;CheckpointerMain&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;//checkpointer会屏蔽SIGTERM，真正的停止是SIGUSR2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGHUP, SignalHandlerForConfigReload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGINT, ReqCheckpointHandler); &lt;span style="color:#75715e"&gt;/* request checkpoint */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGTERM, SIG_IGN); &lt;span style="color:#75715e"&gt;/* ignore SIGTERM */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGQUIT, SignalHandlerForCrashExit);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGALRM, SIG_IGN);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGPIPE, SIG_IGN);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR1, procsignal_sigusr1_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR2, SignalHandlerForShutdownRequest);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;要注意&lt;code&gt;SIGUSR1&lt;/code&gt;和&lt;code&gt;SIGUSR2&lt;/code&gt;，同时要注意checkpointer是没有注册&lt;code&gt;SIGTERM&lt;/code&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%81%9c%e5%ba%93%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;pm信号处理和状态机
 &lt;div id="pm信号处理和状态机" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pm%e4%bf%a1%e5%8f%b7%e5%a4%84%e7%90%86%e5%92%8c%e7%8a%b6%e6%80%81%e6%9c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pmdie&lt;/code&gt;函数用于处理不同的postmaster signals，包括子进程给pm发送的&lt;code&gt;SIGCHILD&lt;/code&gt;和&lt;code&gt;pg_ctl&lt;/code&gt;发送的停库信号。pm信号处理主体逻辑是根据signal转换&lt;code&gt;pmState&lt;/code&gt;状态机状态，并进入状态机&lt;code&gt;PostmasterStateMachine&lt;/code&gt;处理。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pmdie&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; * pmdie -- signal handler for processing various postmaster signals.
&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;pmdie&lt;/span&gt;(SIGNAL_ARGS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;			save_errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; errno;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;switch&lt;/span&gt; (postgres_signal_arg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; SIGTERM:&lt;span style="color:#75715e"&gt;//Smart Shutdown
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_RUN)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				connsAllowed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ALLOW_SUPERUSER_CONNS;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//smart shutdown没有处理pmstate，直接交给状态机处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//此时正常情况pmState = PM_RUN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;PostmasterStateMachine&lt;/span&gt;();
&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; SIGINT:&lt;span style="color:#75715e"&gt;//Fast Shutdown
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_RUN &lt;span style="color:#f92672"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					 pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_HOT_STANDBY)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* Report that we&amp;#39;re about to zap live client sessions */&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;(LOG,
&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;aborting any active transactions&amp;#34;&lt;/span&gt;)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_STOP_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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//Fast Shutdown将pmstate转换为PM_STOP_BACKENDS
&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;PostmasterStateMachine&lt;/span&gt;();
&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; SIGQUIT:&lt;span style="color:#75715e"&gt;//Immediate Shutdown
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span 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;TerminateChildren&lt;/span&gt;(SIGQUIT);&lt;span style="color:#75715e"&gt;//abort all children with SIGQUIT, wait for them to exit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_WAIT_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;/* set stopwatch for them to die */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			AbortStartTime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&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;//Immediate Shutdown将pmstate转换为PM_WAIT_BACKENDS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//进入状态机前处理也会children
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//先用SIGQUIT中断children，等待他们退出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//然后用SIGKILL处理还在的children
&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;PostmasterStateMachine&lt;/span&gt;();
&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;在进入状态机处理函数前先看下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-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;	PM_INIT,					&lt;span style="color:#75715e"&gt;/* postmaster starting */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_STARTUP,					&lt;span style="color:#75715e"&gt;/* waiting for startup subprocess */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_RECOVERY,				&lt;span style="color:#75715e"&gt;/* in archive recovery mode */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_HOT_STANDBY,				&lt;span style="color:#75715e"&gt;/* in hot standby mode */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_RUN,						&lt;span style="color:#75715e"&gt;/* normal &amp;#34;database is alive&amp;#34; state */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_STOP_BACKENDS,			&lt;span style="color:#75715e"&gt;/* need to stop remaining backends */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_WAIT_BACKENDS,			&lt;span style="color:#75715e"&gt;/* waiting for live backends to exit */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_SHUTDOWN,				&lt;span style="color:#75715e"&gt;/* waiting for checkpointer to do shutdown
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;								 * ckpt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_SHUTDOWN_2,				&lt;span style="color:#75715e"&gt;/* waiting for archiver and walsenders 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;								 * finish */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_WAIT_DEAD_END,			&lt;span style="color:#75715e"&gt;/* waiting for dead_end children to exit */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	PM_NO_CHILDREN				&lt;span style="color:#75715e"&gt;/* all important children have exited */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} PMState;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由于正常都是running态关库，这里只需要关注&lt;code&gt;PM_RUN&lt;/code&gt;以下的状态即可。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PostmasterStateMachine&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; * Advance the postmaster&amp;#39;s state machine and take actions as appropriate
&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 is common code for pmdie(), reaper() and sigusr1_handler(), 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; * receive the signals that might mean we need to change state.
&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;PostmasterStateMachine&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:#75715e"&gt;//smart shutdown，此时的pmState应是PM_RUN
&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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_RUN &lt;span style="color:#f92672"&gt;||&lt;/span&gt; pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_HOT_STANDBY)
&lt;/span&gt;&lt;/span&gt;&lt;span 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; (connsAllowed &lt;span style="color:#f92672"&gt;==&lt;/span&gt; ALLOW_NO_CONNS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//当所有normal backend都退出后，pmState转换PM_STOP_BACKENDS
&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;CountChildren&lt;/span&gt;(BACKEND_TYPE_NORMAL) &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;				pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_STOP_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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//PM_STOP_BACKENDS会中止一些比较核心的子进程，有些子进程会继续运行
&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，bgwriter，walwriter，startup，walreiver会停止
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//walsender，checkpointer, archiver, stats, and syslogger会继续跑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//smart shutdown后段会进入此逻辑，fast shutdown直接进入此逻辑
&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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_STOP_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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//注意walsender这句话！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Signal all backend children except walsenders */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SignalSomeChildren&lt;/span&gt;(SIGTERM,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						 BACKEND_TYPE_ALL &lt;span style="color:#f92672"&gt;-&lt;/span&gt; BACKEND_TYPE_WALSND);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* and the autovac launcher too */&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; (AutoVacPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(AutoVacPID, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* and the bgwriter too */&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; (BgWriterPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(BgWriterPID, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* and the walwriter too */&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; (WalWriterPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(WalWriterPID, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* If we&amp;#39;re in recovery, also stop startup and walreceiver procs */&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; (StartupPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(StartupPID, SIGTERM);
&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; (WalReceiverPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(WalReceiverPID, SIGTERM);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* checkpointer, archiver, stats, and syslogger may continue for now */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//将pmState从PM_STOP_BACKENDS转换为PM_WAIT_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;//PM_WAIT_BACKEND表示等待backend退出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_WAIT_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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#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 are in a state-machine state that implies waiting for backends 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;	 * exit, see if they&amp;#39;re all gone, and change state if so.
&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;//smart shutdown,fast shutdown后段会进入此逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//immediate shutdown进入状态机处理时，直接进入此逻辑
&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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_WAIT_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;//crash recovery和immediate shutdown时，checkpointer需要妥善退出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//archiver, stats, and syslogger不需要处理，因为他们没有连到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;//Walsenders也不需要处理，它将在checkpoint记录写入之后退出，就像archiver进程一样
&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;CountChildren&lt;/span&gt;(BACKEND_TYPE_ALL &lt;span style="color:#f92672"&gt;-&lt;/span&gt; BACKEND_TYPE_WALSND) &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;			StartupPID &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;			WalReceiverPID &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;			BgWriterPID &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;			(CheckpointerPID &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			 (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;FatalError &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; Shutdown &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; ImmediateShutdown)) &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;			WalWriterPID &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;			AutoVacPID &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;if&lt;/span&gt; (Shutdown &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; ImmediateShutdown &lt;span style="color:#f92672"&gt;||&lt;/span&gt; FatalError)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//ImmediateShutdown会等待dead end进程结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_WAIT_DEAD_END;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 already SIGQUIT&amp;#39;d the archiver and stats processes, 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;				 * any, when we started immediate shutdown or entered
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * FatalError state.
&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;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;//smart，fast shutdown走此逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//常规子进程都退出了，此时该通知checkpointer做shutdown checkpoint
&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;(Shutdown &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; NoShutdown);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (CheckpointerPID &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;					CheckpointerPID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StartCheckpointer&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* And tell it to shut down */&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; (CheckpointerPID &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;//向Checkpointer发送SIGUSR2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//pmState = PM_SHUTDOWN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;signal_child&lt;/span&gt;(CheckpointerPID, SIGUSR2);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_SHUTDOWN;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;//没有启动起来Checkpointer是一个比较严重的问题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					FatalError &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;					pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_WAIT_DEAD_END;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#75715e"&gt;/* Kill the walsenders, archiver and stats collector 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;//注释说kill walsender，实际上根本没有；至少不是SIGQUIT去停的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;SignalChildren&lt;/span&gt;(SIGQUIT);
&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; (PgArchPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(PgArchPID, SIGQUIT);
&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; (PgStatPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(PgStatPID, SIGQUIT);
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#75715e"&gt;//pmdie函数和状态机函数不会制造PM_SHUTDOWN_2这个状态，但是reaper会
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//reaper在处理checkpointer的退出时，会设置pmState = PM_SHUTDOWN_2；当然在reaper函数最后会进入状态机函数，也就是这里
&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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_SHUTDOWN_2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * PM_SHUTDOWN_2 state ends when there&amp;#39;s no other children than
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * dead_end children left. There shouldn&amp;#39;t be any regular backends
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * left by now anyway; what we&amp;#39;re really waiting for is walsenders 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;		 * archiver.
&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;//PM_SHUTDOWN_2本质上是等待walsender和archiver
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//只是更改了pmState状态
&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; (PgArchPID &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 style="color:#a6e22e"&gt;CountChildren&lt;/span&gt;(BACKEND_TYPE_ALL) &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;			pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_WAIT_DEAD_END;
&lt;/span&gt;&lt;/span&gt;&lt;span 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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_WAIT_DEAD_END)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//PM_WAIT_DEAD_END表示BackendList已经完全清空
&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;dlist_is_empty&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;BackendList) &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;			PgArchPID &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; PgStatPID &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;/* These other guys should be dead already */&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;(StartupPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(WalReceiverPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(BgWriterPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(CheckpointerPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(WalWriterPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(AutoVacPID &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;/* syslogger is not considered here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_NO_CHILDREN;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//PM_NO_CHILDREN是停库的最后一个状态，表示可以正常停库了
&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; (Shutdown &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; NoShutdown &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_NO_CHILDREN)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (FatalError)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ereport&lt;/span&gt;(LOG, (&lt;span style="color:#a6e22e"&gt;errmsg&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;abnormal database system shutdown&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;//异常退出pm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ExitPostmaster&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 	&lt;span style="color:#75715e"&gt;//正常退出pm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ExitPostmaster&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;	...
&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;reaper&lt;/code&gt;是进程回收函数，子进程退出后会发送pm &lt;code&gt;SIGCHLD&lt;/code&gt;信号，pm通过&lt;code&gt;reaper&lt;/code&gt;函数清理进程。 如backend、startup、checkpointer等进程都有自己的清理流程。&lt;/p&gt;
&lt;p&gt;这里只看checkpointer的清理，另外&lt;code&gt;reaper&lt;/code&gt;中没有关于walsender的清理逻辑：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; (pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; CheckpointerPID)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			CheckpointerPID &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;//Checkpointer进程是正常退出，且pmState为PM_SHUTDOWN:等待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;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;EXIT_STATUS_0&lt;/span&gt;(exitstatus) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_SHUTDOWN)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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, we saw normal exit of the checkpointer after it&amp;#39;s been
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * told to shut down. We expect that it wrote a shutdown
&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. (If for some reason it didn&amp;#39;t, recovery 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;				 * occur on next postmaster start.)
&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 this point we should have no normal backend children
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * left (else we&amp;#39;d not be in PM_SHUTDOWN state) but we might
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * have dead_end children to wait 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;				 *
&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 have an archiver subprocess, tell it to do a last
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * archive cycle and quit. Likewise, if we have walsender
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * processes, tell them to send any remaining WAL and quit.
&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;(Shutdown &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; NoShutdown);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;//最后一次唤醒pgarch
&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; (PgArchPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(PgArchPID, SIGUSR2); &lt;span style="color:#75715e"&gt;//pgarch SIGUSR2=pgarch_waken_stop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//最后一次唤醒walsender
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;SignalChildren&lt;/span&gt;(SIGUSR2);&lt;span style="color:#75715e"&gt;//walsender SIGUSR2=WalSndLastCycleHandler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//这里设置了PM_SHUTDOWN_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;//此时Checkpointer正常退出完成了，这里应该等pgarch和walsender最后一个任务完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//即PM_SHUTDOWN_2态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_SHUTDOWN_2;
&lt;/span&gt;&lt;/span&gt;&lt;span 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//checkpointer进程异常退出都认为是crash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;HandleChildCrash&lt;/span&gt;(pid, exitstatus,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;checkpointer process&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&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//最后reaper还是会进入状态机函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;PostmasterStateMachine&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span 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;h3 class="relative group"&gt;checkpointer和walsender进程的退出
 &lt;div id="checkpointer和walsender进程的退出" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#checkpointer%e5%92%8cwalsender%e8%bf%9b%e7%a8%8b%e7%9a%84%e9%80%80%e5%87%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;checkpointer主循环处理请求和关闭进程：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;CheckpointerMain&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:#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;	 * Loop forever
&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;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;		do_checkpoint &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 style="color:#66d9ef"&gt;int&lt;/span&gt;			flags &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;pg_time_t&lt;/span&gt;	now;
&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;			elapsed_secs;
&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;			cur_timeout;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Clear any already-pending wakeups */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ResetLatch&lt;/span&gt;(MyLatch);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * Process any requests or signals received recently.
&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:#a6e22e"&gt;AbsorbSyncRequests&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;HandleCheckpointerInterrupts&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;checkpointer关闭函数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Process any new interrupts.
&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;HandleCheckpointerInterrupts&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:#66d9ef"&gt;if&lt;/span&gt; (ShutdownRequestPending)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * From here on, elog(ERROR) should end with exit(1), not send control
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * back to the sigsetjmp block above
&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;		ExitOnAnyError &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;ShutdownXLOG&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:#75715e"&gt;//这里会写shutdown 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;proc_exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&lt;span style="color:#75715e"&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;checkpointer的退出需要等待&lt;code&gt;ShutdownXLOG&lt;/code&gt;完成。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ShutdownXLOG&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; * This must be called ONCE during postmaster or standalone-backend shutdown
&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;ShutdownXLOG&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; code, Datum arg)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//这里有个checkpointer的shutting down的日志，这个日志一般都会看到
&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;(IsPostmasterEnvironment &lt;span style="color:#f92672"&gt;?&lt;/span&gt; LOG : NOTICE,
&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;shutting down&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;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * Signal walsenders to move to stopping state.
&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;//walsender初始化stopping
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;WalSndInitStopping&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//等待所有walsender处于stopping状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;WalSndWaitStopping&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;RecoveryInProgress&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;CreateRestartPoint&lt;/span&gt;(CHECKPOINT_IS_SHUTDOWN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; CHECKPOINT_IMMEDIATE);
&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;/*
&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 archiving is enabled, rotate the last XLOG file so that all 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;		 * remaining records are archived (postmaster wakes up the archiver
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * process one more time at the end of shutdown). The 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;		 * record will go to the next XLOG file and won&amp;#39;t be archived (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;		 */&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;XLogArchivingActive&lt;/span&gt;() &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;XLogArchiveCommandSet&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RequestXLogSwitch&lt;/span&gt;(false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//这里就是shutdown checkpoint的创建函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;CreateCheckPoint&lt;/span&gt;(CHECKPOINT_IS_SHUTDOWN &lt;span style="color:#f92672"&gt;|&lt;/span&gt; CHECKPOINT_IMMEDIATE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ShutdownCLOG&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;ShutdownCommitTs&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;ShutdownSUBTRANS&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;ShutdownMultiXact&lt;/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;checkpointer通知所有walsender开始stopping：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Signal all walsenders to move to stopping state.
&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 will trigger walsenders to move to a state where no further WAL can be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * generated. See this file&amp;#39;s header for details.
&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;WalSndInitStopping&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;int&lt;/span&gt;			i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_wal_senders; i&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;		WalSnd	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;walsnd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;WalSndCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;walsnds[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;pid_t&lt;/span&gt;		pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;SpinLockAcquire&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&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; walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (pid &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;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:#a6e22e"&gt;SendProcSignal&lt;/span&gt;(pid, PROCSIG_WALSND_INIT_STOPPING, InvalidBackendId);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;walsender通过&lt;code&gt;SendProcSignal&lt;/code&gt;函数收到信号，信号为&lt;code&gt;SIGUSR1&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; * SendProcSignal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		Send a signal to a Postgres process
&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; * Providing backendId is optional, but it will speed up the operation.
&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 success (a signal was sent), zero is 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; * On error, -1 is returned, and errno is set (typically to ESRCH or EPERM).
&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; * Not to be confused with ProcSendSignal
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;SendProcSignal&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;pid_t&lt;/span&gt; pid, ProcSignalReason reason, BackendId backendId)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * BackendId not provided, so search the array using pid. We search
&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 array back to front so as to reduce search overhead. Passing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * InvalidBackendId means that the target is most likely an auxiliary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * process, which will have a slot near the end of the 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;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;			i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NumProcSignalSlots &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i&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;			slot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ProcSignal&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;psh_slot[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pss_pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; pid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 above note about race conditions applies here too */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* Atomically set the proper flag */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;pss_signalFlags[reason] &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:#75715e"&gt;/* Send signal */&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;kill&lt;/span&gt;(pid, SIGUSR1);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ESRCH;
&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:#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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;walsender中&lt;code&gt;SIGUSR1&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:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR1, procsignal_sigusr1_handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pqsignal&lt;/span&gt;(SIGUSR2, WalSndLastCycleHandler);	&lt;span style="color:#75715e"&gt;/* request a last cycle 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;												 * shutdown */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;sigusr1根据信号的reason来分类处理&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * procsignal_sigusr1_handler - handle SIGUSR1 signal.
&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;procsignal_sigusr1_handler&lt;/span&gt;(SIGNAL_ARGS)
&lt;/span&gt;&lt;/span&gt;&lt;span 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; (&lt;span style="color:#a6e22e"&gt;CheckProcSignal&lt;/span&gt;(PROCSIG_WALSND_INIT_STOPPING))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;HandleWalSndInitStopping&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span 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;PROCSIG_WALSND_INIT_STOPPING&lt;/code&gt;的函数为&lt;code&gt;HandleWalSndInitStopping&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; * Handle PROCSIG_WALSND_INIT_STOPPING signal.
&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;HandleWalSndInitStopping&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:#a6e22e"&gt;Assert&lt;/span&gt;(am_walsender);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 replication has not yet started, die like with SIGTERM. 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;	 * replication is active, only set a flag and wake up the main loop. 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;	 * will send any outstanding WAL, wait for it to be replicated to 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;	 * standby, and then exit gracefully.
&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;replication_active)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;kill&lt;/span&gt;(MyProcPid, SIGTERM);
&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;		got_STOPPING &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true;&lt;span style="color:#75715e"&gt;//如果walsender是active的，initstopping函数只会设置状态，让主循环去处理
&lt;/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;这个注释中的main loop有点意义不明，walsender有主循环&lt;code&gt;ServerLoop&lt;/code&gt;，但实际上只有&lt;code&gt;WalSndWaitForWal&lt;/code&gt;中的循环才有关于&lt;code&gt;got_STOPPING&lt;/code&gt;的判断。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WalSndWaitForWal&lt;/code&gt;函数是walsender等待新的wal日志的主循环函数。由于wal record生成之初还在内存中，walwriter会根据一定的条件flush，不是随时都flush。&lt;code&gt;WalSndWaitForWal&lt;/code&gt;函数通过对比当前sent的LSN和flushed的LSN，以判断是否需要send新的wal日志。换句话说，没有flush的wal不会传递，flush过的wal才会传给下游。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WalSndWaitForWal&lt;/code&gt;关于stopping的代码段：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Wait till WAL &amp;lt; loc is flushed to disk so it can be safely sent to client.
&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; * Returns end LSN of flushed WAL. Normally this will be &amp;gt;= loc, but
&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 detect a shutdown request (either from postmaster or client)
&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 will return early, so caller must always check.
&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; XLogRecPtr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;WalSndWaitForWal&lt;/span&gt;(XLogRecPtr loc)
&lt;/span&gt;&lt;/span&gt;&lt;span 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; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//收到got_STOPPING信息后，做一次flush wal操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//这是必须的！因为walwriter进程在此时可能已经关闭了，可能还有wal没有刷盘
&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; (got_STOPPING)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;XLogBackgroundFlush&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 our idea of the currently flushed position. */&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;RecoveryInProgress&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			RecentFlushPtr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetFlushRecPtr&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;			RecentFlushPtr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetXLogReplayRecPtr&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;//跳出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;//有了新的RecentFlushPtr位置后，还需要send
&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; (got_STOPPING)
&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 style="color:#75715e"&gt;/* reactivate latch so WalSndLoop knows to continue */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;SetLatch&lt;/span&gt;(MyLatch);
&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; RecentFlushPtr;
&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;回到walsender主循环：&lt;code&gt;WalSndLoop(XLogSendLogical)&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;/* Main loop of walsender process that streams the WAL over Copy messages. */&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;WalSndLoop&lt;/span&gt;(WalSndSendDataCallback send_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:#66d9ef"&gt;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Clear any already-pending wakeups */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;ResetLatch&lt;/span&gt;(MyLatch);
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#a6e22e"&gt;ProcessRepliesIfAny&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 have received CopyDone from the client, sent CopyDone
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * ourselves, and the output buffer is empty, it&amp;#39;s time to exit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * streaming.
&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;//streaming做完就退出循环
&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; (streamingDoneReceiving &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; streamingDoneSending &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;pq_is_send_pending&lt;/span&gt;())
&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:#75715e"&gt;//output buffer是否还有pending的data，有就send
&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;pq_is_send_pending&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;send_data&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;			WalSndCaughtUp &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;/* Try to flush pending output to the client */&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;pq_flush_if_writable&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:#a6e22e"&gt;WalSndShutdown&lt;/span&gt;();&lt;span style="color:#75715e"&gt;//下游不可写入，下游端关闭了，正常关闭walsender，退出码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;/* If nothing remains to be sent right now ... */&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; (WalSndCaughtUp &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;pq_is_send_pending&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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&amp;#39;re in catchup state, move to streaming. This is an
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * important state change for users to know about, since 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;			 * this point data loss might occur if the primary dies and 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;			 * need to failover to the standby. The state change is also
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * important for synchronous replication, since commits 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;			 * started to wait at that point might wait for some time.
&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; (MyWalSnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;==&lt;/span&gt; WALSNDSTATE_CATCHUP)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ereport&lt;/span&gt;(DEBUG1,
&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;&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 now caught up with upstream server&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								application_name)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;WalSndSetState&lt;/span&gt;(WALSNDSTATE_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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//收到SIGUSR2，表示shutdown 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;//把shutdown checkpoint 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;if&lt;/span&gt; (got_SIGUSR2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;WalSndDone&lt;/span&gt;(send_data);&lt;span style="color:#75715e"&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;		...
&lt;/span&gt;&lt;/span&gt;&lt;span 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;走远了，回到checkpointer的&lt;code&gt;ShutdownXLOG&lt;/code&gt;逻辑，以上只是在分析&lt;code&gt;WalSndInitStopping()&lt;/code&gt;。这个信号发送给walsender后，会执行&lt;code&gt;WalSndWaitStopping&lt;/code&gt;以等待walsender。&lt;/p&gt;
&lt;p&gt;只要有walsender没有退出，这里就是一个死循环不会return：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Wait that all the WAL senders have quit or reached the stopping state. 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; * is used by the checkpointer to control when the shutdown checkpoint 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; * safely be performed.
&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;WalSndWaitStopping&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;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;			i;
&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;		all_stopped &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;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_wal_senders; i&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;			WalSnd	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;walsnd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;WalSndCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;walsnds[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;SpinLockAcquire&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (walsnd&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&gt;&lt;/span&gt;&lt;span style="display: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;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; WALSNDSTATE_STOPPING)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				all_stopped &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 style="color:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&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:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* safe to leave if confirmation is done for all WAL senders */&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; (all_stopped)
&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:#a6e22e"&gt;pg_usleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10000L&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* wait for 10 msec */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;最后结合walsender.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; If the server is shut down, checkpointer sends us
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; PROCSIG_WALSND_INIT_STOPPING after all regular backends have exited. If
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; the backend is idle or runs an SQL query this causes the backend 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; shutdown, &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; logical replication is in progress all existing WAL 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; are processed followed by a shutdown. Otherwise this causes the walsender
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; to &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; to the &lt;span style="color:#e6db74"&gt;&amp;#34;stopping&amp;#34;&lt;/span&gt; state. In this state, the walsender will reject
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; any further replication commands. The checkpointer begins the shutdown
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; checkpoint once all walsenders are confirmed as stopping. When the shutdown
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; checkpoint finishes, the postmaster sends us SIGUSR2. This instructs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; walsender to send any outstanding WAL, including the shutdown checkpoint
&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, wait &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; it to be replicated to the standby, and then exit.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;当所有的常规backend都退出后，checkpointer会发送&lt;code&gt;PROCSIG_WALSND_INIT_STOPPING&lt;/code&gt;给walsender&lt;/li&gt;
&lt;li&gt;walsender可能进入stopping状态&lt;/li&gt;
&lt;li&gt;当所有walsender都进入stopping状态后，checkpointer才会做shutdown checkpoint&lt;/li&gt;
&lt;li&gt;当shutdown checkpoint完成后，pm发送&lt;code&gt;SIGUSR2&lt;/code&gt;给walsender，walsender会发送额外的wal，包括shutdown checkpoint记录本身，并等待standby完成再退出&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%81%9c%e5%ba%93%e6%b5%81%e7%a8%8b%e5%9b%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;撸完源码好像懂了又好像没懂，需要一个停库流程图来理清思路。
汇总fast shutdown停库流程图：



&lt;img src="https://lastdba.com/img/csdn/464a8c3e13dd.png" alt="pg fast停库流程.png" /&gt;&lt;/p&gt;
&lt;p&gt;（高清大图：&lt;a href="https://www.processon.com/view/link/6778a73a04a8344b9502637a" target="_blank" rel="noreferrer"&gt;https://www.processon.com/view/link/6778a73a04a8344b9502637a&lt;/a&gt;）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PG通过信号、各进程主循环、PM状态机、pmdie进程回收函数来共同管理停库逻辑&lt;/li&gt;
&lt;li&gt;还需注意：信号本身是异步的。如果需要等待目标进程处理信号的结果，通常需要通过其他同步机制（如管道、信号量、共享内存等）来实现。PG主要通过进程依赖和进程是否正常退出来判断信号是否被正确处理。&lt;/li&gt;
&lt;li&gt;pgarch、walsender被认为是同一类进程，与其他进程（walwriter、bgwriter）等处理不同。pgarch、walsender需要额外做“&lt;strong&gt;最后一个任务&lt;/strong&gt;”这件事。“&lt;strong&gt;最后一个任务&lt;/strong&gt;”的信号通常定义为SIGUSR2&lt;/li&gt;
&lt;li&gt;checkpointer的正常退出依赖pgarch、walsender的正常退出&lt;/li&gt;
&lt;li&gt;pgarch的最后一个任务是最后一次归档。所以归档会影响停库&lt;/li&gt;
&lt;li&gt;walsender的倒数第二个任务是传递最后的wal，最后一个任务是传递checkpoint shutdown信息。且这些任务需要下游回复消息，所以walsender会影响停库。&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%b5%8b%e8%af%95%e5%a4%8d%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;测试：复现walsender阻止停库
 &lt;div id="测试复现walsender阻止停库" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a4%8d%e7%8e%b0walsender%e9%98%bb%e6%ad%a2%e5%81%9c%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在fast stop停库后，walsender可能阻止停库。&lt;/p&gt;
&lt;p&gt;测试了各自场景去复现walsender阻止停库，目前来看以下条件同时满足比较容易触发停库异常：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发布订阅一个walsender&lt;/li&gt;
&lt;li&gt;dts一个walsender&lt;/li&gt;
&lt;li&gt;大量子事务导致复制槽spill中&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-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:#ae81ff"&gt;1&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;--pg
&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; lzlpg(id bigserial &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,a char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;),b char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; 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:#75715e"&gt;--oracle
&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.lzloracle(id number &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; ,a char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;),b char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; char(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;)) tablespace FADATA;
&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:#960050;background-color:#1e0010"&gt;搭建&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;dts到oracle&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:#ae81ff"&gt;3&lt;/span&gt;.&lt;span style="color:#960050;background-color:#1e0010"&gt;改小&lt;/span&gt;logical_decoding_work_mem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;logical_decoding_work_mem&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;MB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;4&lt;/span&gt;.&lt;span style="color:#960050;background-color:#1e0010"&gt;写入大量数据（推荐子事务&lt;/span&gt;spill&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;--一次insert一行，每个insert一个子事务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;begin;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;subtx.&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 style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;500000&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;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;savepoint p$i;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;subtx.&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; echo &lt;span style="color:#e6db74"&gt;&amp;#34;insert into lzlpg(column1,column2,column3) select &amp;#39;a&amp;#39;,&amp;#39;b&amp;#39;,&amp;#39;c&amp;#39;;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;subtx.&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;done
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nohup psql &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzl &lt;span style="color:#f92672"&gt;-&lt;/span&gt;f subtx.&lt;span style="color:#66d9ef"&gt;sql&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;5&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;pg_ctl stop &lt;span style="color:#f92672"&gt;-&lt;/span&gt;D &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;PGDATA &lt;span style="color:#f92672"&gt;-&lt;/span&gt;m fast&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时fast停库，数据库处于一个非完整停库状态，如下:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;~/lzl/slot&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ps -axjf|grep &lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;150696&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;64964&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;64961&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;146782&lt;/span&gt; pts/42 &lt;span style="color:#ae81ff"&gt;64961&lt;/span&gt; S+ &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto &lt;span style="color:#ae81ff"&gt;110402&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:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 /myhost/postgres/base/rasesql1.5.6/bin/postgres -D /myhost/pg8094/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;110599&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;110599&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;110599&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: logger 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117803&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117803&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117803&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: checkpointer 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117807&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117807&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117807&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: stats collector 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;118563&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;118563&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;118563&lt;/span&gt; ? -1 Rs &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 3:29 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: walsender lzl 127.0.0.1&lt;span style="color:#f92672"&gt;(&lt;/span&gt;62971&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;110402&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;222918&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;222918&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;222918&lt;/span&gt; ? -1 Rs &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 2:59 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: walsender dtssync 30.181.46.203&lt;span style="color:#f92672"&gt;(&lt;/span&gt;57218&lt;span style="color:#f92672"&gt;)&lt;/span&gt; idle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;walsender、checkpointer、postmaster都在，logger、stats也没有退出。&lt;/p&gt;
&lt;p&gt;控制文件的状态为&lt;code&gt;in production&lt;/code&gt;：生产运行中，说明checkpoint做的本地shutdown 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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/lzl/slot&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pg_controldata|grep -i state
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database cluster state: in production&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;checkpointer堆栈：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;pstack &lt;span style="color:#ae81ff"&gt;117803&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#0 0x00002b879fe0b983 in __select_nocancel () from /lib64/libc.so.6
&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 0x00000000008fd04a in pg_usleep (microsec=microsec@entry=10000) at pgsleep.c:56
&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 0x00000000007610c8 in WalSndWaitStopping () at walsender.c:3209
&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 0x000000000051fa86 in ShutdownXLOG (code=code@entry=0, arg=arg@entry=0) at xlog.c:8596
&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 0x00000000007215ff in HandleCheckpointerInterrupts () at checkpointer.c:566
&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 CheckpointerMain () at checkpointer.c:343
&lt;/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;此时的checkpointer堵在&lt;code&gt;WalSndWaitStopping&lt;/code&gt;函数，代表checkpointer在等待walsender进程进入stopping状态。&lt;/p&gt;
&lt;p&gt;此时的walsender堆栈：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;#0 0x00000000007484fb in ReorderBufferLargestTXN (rb=&amp;lt;optimized out&amp;gt;) at reorderbuffer.c:2345
&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 ReorderBufferCheckMemoryLimit (rb=0x2b8808b94118) at reorderbuffer.c:2390
&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 ReorderBufferQueueChange (rb=0x2b8808b94118, xid=&amp;lt;optimized out&amp;gt;, lsn=1676456602544, change=change@entry=0x2b87a229f408) at reorderbuffer.c:649
&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 0x000000000073ec99 in DecodeTruncate (buf=&amp;lt;optimized out&amp;gt;, buf=&amp;lt;optimized out&amp;gt;, ctx=&amp;lt;optimized out&amp;gt;) at decode.c:872
&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 DecodeHeapOp (buf=0x7ffda7d35180, ctx=0x2b87a224b118) at decode.c:455
&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 LogicalDecodingProcessRecord (ctx=0x2b87a224b118, record=&amp;lt;optimized out&amp;gt;) at decode.c:126
&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 0x000000000075f502 in XLogSendLogical () at walsender.c:2886
&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 0x0000000000761822 in WalSndLoop (send_data=send_data@entry=0x75f4c0 &amp;lt;XLogSendLogical&amp;gt;) at walsender.c:2287
&lt;/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;walsender堵在事务溢出函数。（&lt;em&gt;为什么堵还没有搞清楚！！！&lt;/em&gt;）&lt;/p&gt;
&lt;p&gt;checkpointer进程阻塞在&lt;code&gt;WalSndWaitStopping&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; * Wait that all the WAL senders have quit or reached the stopping state. 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; * is used by the checkpointer to control when the shutdown checkpoint 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; * safely be performed.
&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;WalSndWaitStopping&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;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;			i;
&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;		all_stopped &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;for&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; max_wal_senders; i&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;			WalSnd	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;walsnd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;WalSndCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;walsnds[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;SpinLockAcquire&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (walsnd&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&gt;&lt;/span&gt;&lt;span style="display: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;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;state &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; WALSNDSTATE_STOPPING)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				all_stopped &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 style="color:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&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:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;walsnd&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* safe to leave if confirmation is done for all WAL senders */&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; (all_stopped)
&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:#a6e22e"&gt;pg_usleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10000L&lt;/span&gt;);		&lt;span style="color:#75715e"&gt;/* wait for 10 msec */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;walsnd-&amp;gt;state != WALSNDSTATE_STOPPIN&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="#%e6%b5%8b%e8%af%95%e5%81%9c%e5%ba%93%e4%b8%ad%e9%97%b4%e6%80%81%e7%9a%84%e5%a4%84%e7%90%86%e6%96%b9%e6%a1%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;以上是个尴尬的停库停一半的状态，除了&lt;code&gt;kill -9&lt;/code&gt; 外，实际上还有其他好办法可以一致性停库。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方案1：关闭下游进程&lt;/li&gt;
&lt;li&gt;方案2：发送&lt;code&gt;SIGTERM&lt;/code&gt;给walsender&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方案1测试：&lt;/p&gt;
&lt;p&gt;由于下游退出后，walsender也会跟随退出：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;ProcessRepliesIfAny&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:#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;				 * &amp;#39;X&amp;#39; means that the standby is closing down the socket.
&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;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;X&amp;#39;&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;proc_exit&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;如果是发布订阅，在订阅端执行以下命令即可，即使是上游处于停库中间态也会将walsender退出。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; SUBSCRIPTION sub_lzl disable;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不过这依赖下游自身的处理，我们也不能快速地关闭dts等同步工具的下游接收进程。&lt;/p&gt;
&lt;p&gt;方案2测试：&lt;/p&gt;
&lt;p&gt;由于walsender注册了&lt;code&gt;SIGTERM&lt;/code&gt;信号，库运行时跑的&lt;code&gt;select pg_terminate_backend($walsender_pid)&lt;/code&gt;命令也是发送&lt;code&gt;SIGTERM&lt;/code&gt;给walsender，所以理论上只要发送&lt;code&gt;SIGTERM&lt;/code&gt;给walsender应该可以处理这个问题，而不必发送&lt;code&gt;kill -9&lt;/code&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;kill &lt;span style="color:#f92672"&gt;-&lt;/span&gt;SIGTERM &lt;span style="color:#ae81ff"&gt;62834&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; kill &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;62834&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; kill &lt;span style="color:#ae81ff"&gt;62834&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;正常kill后pm等进程全部退出。&lt;/p&gt;
&lt;p&gt;查看控制文件和wal日志信息以确认是否是一致性停库：&lt;/p&gt;
&lt;p&gt;1.pg_controldata的数据库state从in production转换为shut down一致性停库：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_controldata|grep -i state
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database cluster state: shut down&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.wal日志的最后一个record是&lt;code&gt;CHECKPOINT_SHUTDOWN&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;pg_waldump 000000010000018600000012|tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_waldump: fatal: error in WAL record at 186/915D7920: invalid record length at 186/915D7998: wanted 24, got &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: XLOG len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 114/ 114, tx: 0, lsn: 186/915D7920, prev 186/915D78A8, desc: CHECKPOINT_SHUTDOWN redo 186/915D7920; tli 1; prev tli 1; fpw true; xid 0:13431045; oid 3808147; multi 3; offset 6; oldest xid &lt;span style="color:#ae81ff"&gt;485&lt;/span&gt; in DB 1; oldest multi &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; in DB 1; oldest/newest commit timestamp xid: 494/13431044; oldest running xid 0; shutdown&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;测试：复现只有主库有CHECKPOINT_SHUTDOWN
 &lt;div id="测试复现只有主库有checkpoint_shutdown" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a4%8d%e7%8e%b0%e5%8f%aa%e6%9c%89%e4%b8%bb%e5%ba%93%e6%9c%89checkpoint_shutdown" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;生产现场有个现象是，本地wal有shutdown checkpoint但是从库没有。生产是在半停库状态时做的immediate stop，随后启动库没有启动起来。&lt;/p&gt;
&lt;p&gt;当时主从的wal日志最后2条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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#主库wal：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHECKPOINT_ONLINE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHECKPOINT_SHUTDOWN
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#从库wal：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHECKPOINT_ONLINE&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;&lt;span style="color:#75715e"&gt;## 1. 先复现walsender阻止停库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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. 查看最后一条wal record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 188/307ABE00, prev 188/307ABDC8, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;13432445&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;13432444&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;13432445&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. pg_ctl stop -D $PGDATA -m i&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. 查看最后一条wal record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;不变，同2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 5. pg_ctl start -D $PGDATA&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. 查看最后两条wal record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmgr: Standby len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 50/ 50, tx: 0, lsn: 188/307ABE00, prev 188/307ABDC8, desc: RUNNING_XACTS nextXid &lt;span style="color:#ae81ff"&gt;13432445&lt;/span&gt; latestCompletedXid &lt;span style="color:#ae81ff"&gt;13432444&lt;/span&gt; oldestRunningXid &lt;span style="color:#ae81ff"&gt;13432445&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;rmgr: XLOG len &lt;span style="color:#f92672"&gt;(&lt;/span&gt;rec/tot&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: 114/ 114, tx: 0, lsn: 188/307ABE38, prev 188/307ABE00, desc: CHECKPOINT_SHUTDOWN redo 188/307ABE38; tli 1; prev tli 1; fpw true; xid 0:13432445; oid 3832732; multi 3; offset 6; oldest xid &lt;span style="color:#ae81ff"&gt;485&lt;/span&gt; in DB 1; oldest multi &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; in DB 1; oldest/newest commit timestamp xid: 494/13432444; oldest running xid 0; shutdown &lt;span style="color:#75715e"&gt;#出现CHECKPOINT_SHUTDOWN&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;CHECKPOINT_SHUTDOWN&lt;/code&gt;其实是&lt;strong&gt;起库&lt;/strong&gt;的时候做！&lt;/p&gt;
&lt;p&gt;这与现场的动作一致：1.fast停库没停下来 2.immediate停库 3.起库没启起来。&lt;/p&gt;
&lt;p&gt;疑问1：起库什么时候做的CHECKPOINT_SHUTDOWN？&lt;/p&gt;
&lt;p&gt;疑问2：CHECKPOINT_ONLINE的触发时机？复现表象来看，偶现fast shutdown出现最后一个wal record为CHECKPOINT_ONLINE&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;疑问1分析：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;起库做shutdown checkpoint，这很容易联想到是startup进程做的。由于之前分析过startup进程的起库流程，我们可以直接定位到函数&lt;code&gt;StartupXLOG&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; * This must be called ONCE during postmaster or standalone-backend startup
&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;StartupXLOG&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;if&lt;/span&gt; (InRecovery) &lt;span style="color:#75715e"&gt;//因为是shutdown停库所以会做实例恢复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * Perform a checkpoint to update all our recovery activity 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;		 * Note that we write a shutdown checkpoint rather than an on-line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * one. This is not particularly critical, but since we may be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * assigning a new TLI, using a shutdown checkpoint allows us to have
&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 rule that TLI only changes in shutdown checkpoints, 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;		 * allows some extra error checking in xlog_redo.
&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;		 * In fast promotion, only create a lightweight end-of-recovery 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;		 * instead of a full checkpoint. A checkpoint is requested later,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * after we&amp;#39;re fully out of recovery mode and already accepting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * queries.
&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; (bgwriterLaunched) &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&gt;&lt;/span&gt;&lt;span style="display: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;//主库的startup会走到这里
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;CreateCheckPoint&lt;/span&gt;(CHECKPOINT_END_OF_RECOVERY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; CHECKPOINT_IMMEDIATE);
&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;做shutdown checkpoint是故意的，主要是为了TLI逻辑的代码健壮性&lt;/li&gt;
&lt;li&gt;只要是非一致性停库，起库的时候就会做shutdown checkpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，直接&lt;code&gt;-m i&lt;/code&gt;暴力停库再起库，也会出现&lt;code&gt;CHECKPOINT_SHUTDOWN&lt;/code&gt;，自测。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;疑问2分析：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;多次测试，偶现，推测是刚好停库前满足checkpoint条件触发了一次online checkpoint，纯属巧合。&lt;/p&gt;
&lt;p&gt;联想数据库停库失败后，无论是脚本、HA还是人工介入都有可能做暴力停库，所以停库前推荐至少做一次checkpoint。&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%e5%bd%92%e6%a1%a3%e5%af%b9%e5%81%9c%e5%ba%93%e7%9a%84%e5%bd%b1%e5%93%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在分析停库代码的时候，还发现checkpointer进程退出后，reaper checkpointer会发送&lt;code&gt;SIGUSR2&lt;/code&gt;给pgarch让其最后一次归档并退出：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;reaper&lt;/span&gt;(SIGNAL_ARGS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; (pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; CheckpointerPID)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			CheckpointerPID &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;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;EXIT_STATUS_0&lt;/span&gt;(exitstatus) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_SHUTDOWN)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* Waken archiver for the last time */&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; (PgArchPID &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:#a6e22e"&gt;signal_child&lt;/span&gt;(PgArchPID, SIGUSR2);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;而pm的退出依赖除syslogger外所有进程的退出：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; (pmState &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PM_WAIT_DEAD_END)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;dlist_is_empty&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;BackendList) &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;			PgArchPID &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; PgStatPID &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;/* These other guys should be dead already */&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;(StartupPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(WalReceiverPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(BgWriterPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(CheckpointerPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(WalWriterPID &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:#a6e22e"&gt;Assert&lt;/span&gt;(AutoVacPID &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;/* syslogger is not considered here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			pmState &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PM_NO_CHILDREN;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/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:#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;archive_mode &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;archive_command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/bin/false ;sleep 1000&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;配置归档永远为&lt;/span&gt;false且设置sleep以绕过NUM_ARCHIVE_RETRIES逻辑
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_ctl stop &lt;span style="color:#f92672"&gt;-&lt;/span&gt;D &lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;PGDATA &lt;span style="color:#f92672"&gt;-&lt;/span&gt;m fast&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;$ ps -axjf|grep &lt;span style="color:#ae81ff"&gt;61470&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;72200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;88406&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;88405&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;68705&lt;/span&gt; pts/48 &lt;span style="color:#ae81ff"&gt;88405&lt;/span&gt; S+ &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto &lt;span style="color:#ae81ff"&gt;61470&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:#ae81ff"&gt;61470&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61470&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61470&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 /myhost/postgres/base/rasesql1.5.6/bin/postgres -D /myhost/pg8094/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;61470&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61772&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61772&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;61772&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: logger 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;61470&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;63880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;63880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;63880&lt;/span&gt; ? -1 Ss &lt;span style="color:#ae81ff"&gt;6001&lt;/span&gt; 0:00 &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt; postgres: lzlpg: archiver archiving &lt;span style="color:#ae81ff"&gt;000000010000018800000007&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为这里的checkpointer已经完整停下来了，数据库是一致状态，所以archiver直接&lt;code&gt;kill -9&lt;/code&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%e5%8f%a5%e8%af%9d%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题1.为什么停库没有停下来？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;walsender阻止了停库。checkpointer给walsender发送SIGUSR1，并无限等待所有walsender进程stopping状态，checkpointer卡在这一步。&lt;/p&gt;
&lt;p&gt;后面停库停下来是因为&lt;code&gt;-m i&lt;/code&gt;暴力停库&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题2.walsender阻止停库中间态是否有其他方案优雅停库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有。给所有walsender发送&lt;code&gt;SIGTERM&lt;/code&gt;信号，既&lt;code&gt;kill&lt;/code&gt;（or &lt;code&gt;kill -15&lt;/code&gt;、&lt;code&gt;kill -SIGTERM&lt;/code&gt;)。随后checkpointer、postmaster会完整停库。&lt;/p&gt;
&lt;p&gt;walsender启动时注册过&lt;code&gt;SIGTERM&lt;/code&gt;信号，测试来看没有处理不了的情况。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SIGTERM&lt;/code&gt;也是&lt;code&gt;pg_terminate_backend(pid)&lt;/code&gt;所发送的信号，也是标准停库时应该执行的命令以停止walsender。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题3.为什么主从库只差一条&lt;code&gt;shutdown checkpoint&lt;/code&gt;？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;3.1主从库都有&lt;code&gt;CHECKPOINT_ONLINE&lt;/code&gt; 的解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主库触发&lt;code&gt;CHECKPOINT_ONLINE&lt;/code&gt;纯属巧合&lt;/li&gt;
&lt;li&gt;由于物理walsender还在，这条wal record传输到了从库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.2只有主库有&lt;code&gt;CHECKPOINT_SHUTDOWN&lt;/code&gt;的解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这条&lt;code&gt;CHECKPOINT_SHUTDOWN&lt;/code&gt;是主库起库的时候做的&lt;/li&gt;
&lt;li&gt;由于主库没有起完，这条wal record没有传到从库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;问题4.archiver为什么会阻止停库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在reaper checkpointer进程时，pm会让archiver做最后一次归档，而pm依赖除syslogger之外的所有进程退出，所以最后一次归档如果够慢或者其他问题，会阻止停库。归档失败不会，归档进程会很快退出。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题5.哪些进程会阻止停库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其实任意进程不退出都会阻止停库，问题在于哪些比较容易搞出事。从停库代码流程来看archiver、walsender会常阻止停库，因为他们在停库阶段会做最后一次归档or日志传递。&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;&lt;a href="https://www.postgresql.org/docs/current/server-shutdown.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/server-shutdown.html&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/Signals" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Signals&lt;/a&gt;
postgres.c
postmaster.c
walsender.c
xlog.c
checkpointer.c
startup.c
pgarch.c&lt;/p&gt;</content:encoded></item><item><title>读书笔记——DDIA-v2 设计数据密集型应用（第二版）</title><link>https://lastdba.com/2024/09/20/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0ddia-v2-%E8%AE%BE%E8%AE%A1%E6%95%B0%E6%8D%AE%E5%AF%86%E9%9B%86%E5%9E%8B%E5%BA%94%E7%94%A8%E7%AC%AC%E4%BA%8C%E7%89%88/</link><pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/09/20/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0ddia-v2-%E8%AE%BE%E8%AE%A1%E6%95%B0%E6%8D%AE%E5%AF%86%E9%9B%86%E5%9E%8B%E5%BA%94%E7%94%A8%E7%AC%AC%E4%BA%8C%E7%89%88/</guid><description>&lt;p&gt;ddia-v2中文版地址：&lt;a href="https://github.com/Vonng/ddia/tree/v2" target="_blank" rel="noreferrer"&gt;https://github.com/Vonng/ddia/tree/v2&lt;/a&gt;
ddia-v2看完感觉爱不释手，只要是数据相关的知识都娓娓道来，为什么会这样？现在是怎样的？这样有什么问题？其中的看法和想法实在精辟、干练，甚至连每个章节的航海图都很有意思。&lt;/p&gt;</description><content:encoded>&lt;p&gt;ddia-v2中文版地址：&lt;a href="https://github.com/Vonng/ddia/tree/v2" target="_blank" rel="noreferrer"&gt;https://github.com/Vonng/ddia/tree/v2&lt;/a&gt;
ddia-v2看完感觉爱不释手，只要是数据相关的知识都娓娓道来，为什么会这样？现在是怎样的？这样有什么问题？其中的看法和想法实在精辟、干练，甚至连每个章节的航海图都很有意思。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;注意：本文只是对原作的一点摘抄，基本没有自己的思路和想法。仅仅是把一些非常爱的东西摘下来，有些已经掌握和太遥远的知识是略过的！&lt;/em&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch1 数据系统架构中的利弊权衡
 &lt;div id="ch1-数据系统架构中的利弊权衡" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch1-%e6%95%b0%e6%8d%ae%e7%b3%bb%e7%bb%9f%e6%9e%b6%e6%9e%84%e4%b8%ad%e7%9a%84%e5%88%a9%e5%bc%8a%e6%9d%83%e8%a1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;OLTP&amp;amp;OLAP
 &lt;div id="oltpolap" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#oltpolap" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;OLTP和分析之间的区别并不总是明确的，但下表列出了一些典型的特征&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;属性&lt;/th&gt;
 &lt;th&gt;业务系统 (OLTP)&lt;/th&gt;
 &lt;th&gt;分析系统 (OLAP)&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;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;主要写入模式&lt;/td&gt;
 &lt;td&gt;创建、更新和删除个别记录&lt;/td&gt;
 &lt;td&gt;批量导入（ETL）或事件流&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;/tr&gt;
 &lt;tr&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;/tr&gt;
 &lt;tr&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;GB,TB&lt;/td&gt;
 &lt;td&gt;TB,PB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;数据仓库&lt;/em&gt;是一个单独的数据库，分析师可以尽情查询，而不影响OLTP操作.数据仓库通常以与OLTP数据库非常不同的方式存储数据，以优化常见于分析的查询类型
将数据获取到数据仓库的过程称为&lt;em&gt;提取-转换-加载&lt;/em&gt;（Extract–Transform–Load,ETL）
有些数据库系统提供&lt;em&gt;混合事务/分析处理&lt;/em&gt;（HTAP），旨在在单一系统中同时启用OLTP和分析，无需从一个系统向另一个系统进行ETL 。
&lt;strong&gt;尽管存在HTAP，由于它们目标和要求的不同，事务性和分析性系统之间的分离仍然很常见&lt;/strong&gt;。特别是，每个业务系统拥有自己的数据库被视为良好的实践，导致有数百个独立的操作数据库；另一方面，一个企业通常只有一个数据仓库，这样业务分析师可以在单个查询中合并来自几个业务系统的数据。
&lt;em&gt;数据湖&lt;/em&gt;一个集中的数据存储库，存放可能对分析有用的任何数据，通过ETL过程从业务系统获取。与数据仓库的不同之处在于，数据湖只包含文件，不强加任何特定的文件格式或数据模型。数据仓库通常使用&lt;em&gt;关系&lt;/em&gt;数据模型，通过SQL查询。
&lt;em&gt;数据湖仓&lt;/em&gt;不仅是单独的数据仓库，还可以直接在数据湖中的文件上运行典型的数据仓库工作负载（SQL查询和商业分析），以及数据科学/机器学习工作负载，这种架构被称为&lt;em&gt;数据湖仓&lt;/em&gt;。它需要一个查询执行引擎和一个元数据（例如，模式管理）层来扩展数据湖的文件存储 。Apache Hive、Spark SQL、Presto和Trino是这种方法的例子。&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%91%e6%9c%8d%e5%8a%a1%e5%92%8c%e8%87%aa%e6%89%98%e7%ae%a1" 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;strong&gt;释放你的团队，专注于更高层次的问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果你的系统负载随时间变化很大，云服务特别有价值&lt;/strong&gt;。如果你配置你的机器能够处理高峰负载，但这些计算资源大部分时间都处于空闲状态，系统的成本效益就会降低。&lt;/li&gt;
&lt;li&gt;与物理机相比，&lt;strong&gt;云实例可以更快地配置，并且大小种类更多&lt;/strong&gt;&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;li&gt;如果它缺少你需要的功能，你唯一能做的就是礼貌地询问供应商是否会添加它；你通常无法自己实现它。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果服务出现故障，你只能等待它恢复&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果你以某种方式使用服务，触发了一个错误或导致性能问题，&lt;strong&gt;你很难诊断问题&lt;/strong&gt;。对于你自己运行的软件，你可以从业务系统获取性能指标和调试信息来帮助你了解其行为，你可以查看服务器日志，但使用供应商托管的服务时，&lt;strong&gt;你通常无法访问这些内部信息&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;此外，如果服务关闭或变得无法接受地昂贵，或者如果供应商决定以你不喜欢的方式更改其产品，你将受制于他们——继续运行软件的旧版本通常不是一个选项，因此你将被迫迁移到另一个服务 。如果有提供兼容API的替代服务，这种风险可以缓解，但对于许多云服务，没有标准的API，这增加了切换的成本，使&lt;strong&gt;供应商锁定&lt;/strong&gt;成为一个问题。&lt;/li&gt;
&lt;li&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%ba%91%e5%8e%9f%e7%94%9f" 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;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;事务型/OLTP&lt;/td&gt;
 &lt;td&gt;MySQL, PostgreSQL, MongoDB&lt;/td&gt;
 &lt;td&gt;AWS Aurora , Azure SQL DB Hyperscale , Google Cloud Spanner&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;分析型/OLAP&lt;/td&gt;
 &lt;td&gt;Teradata, ClickHouse, Spark&lt;/td&gt;
 &lt;td&gt;Snowflake , Google BigQuery, Azure Synapse Analytics&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;云原生服务的关键思想是不仅使用由业务系统管理的计算资源，还要构建在更低层级的云服务之上，创建更高层级的服务。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;对象存储&lt;/em&gt;服务，如亚马逊 S3、Azure Blob 存储和 Cloudflare R2 存储大文件。它们提供的 API 比典型文件系统的 API 更有限（基本的文件读写），但它们的优势在于隐藏了底层的物理机器：服务自动将数据分布在许多机器上，因此你无需担心任何一台机器上的磁盘空间耗尽。即使某些机器或其磁盘完全失败，也不会丢失数据。&lt;/li&gt;
&lt;li&gt;许多其他服务又是建立在对象存储和其他云服务之上的：例如，Snowflake 是一种基于云的分析数据库（数据仓库），依赖于 S3 进行数据存储 ，还有一些服务又建立在 Snowflake 之上。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;云原生系统通常是&lt;em&gt;多租户&lt;/em&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%91%e6%97%b6%e4%bb%a3%e7%9a%84%e8%bf%90%e8%90%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;传统上，管理组织服务器端数据基础设施的人被称为数据库管理员（DBAs）或系统管理员（sysadmins）。近年来，许多组织试图将软件开发和运营的角色整合到一个团队中，共同负责后端服务和数据基础设施；&lt;em&gt;DevOps&lt;/em&gt;哲学指导了这一趋势。&lt;em&gt;站点可靠性工程师&lt;/em&gt;（SREs）是谷歌实施这一理念的方式。
DevOps/SRE哲学更加强调：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自动化&lt;/strong&gt;——偏好可重复的过程而不是一次性的手工作业，&lt;/li&gt;
&lt;li&gt;偏好短暂的虚拟机和服务而不是长时间运行的服务器，&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;促进频繁的应用更新&lt;/strong&gt;，&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;从事件中学习&lt;/strong&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;h2 class="relative group"&gt;ch2 定义非功能性要求
 &lt;div id="ch2-定义非功能性要求" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch2-%e5%ae%9a%e4%b9%89%e9%9d%9e%e5%8a%9f%e8%83%bd%e6%80%a7%e8%a6%81%e6%b1%82" 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%a1%ac%e4%bb%b6%e5%92%8c%e8%bd%af%e4%bb%b6%e7%bc%ba%e9%99%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在大规模系统中，硬件故障发生得足够频繁，以至于它们成为正常系统运作的一部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每年大约有 2-5% 的磁盘硬盘出现故障；在一个拥有 10,000 块硬盘的存储集群中，我们因此可以预计平均每天会有一块硬盘故障。&lt;/li&gt;
&lt;li&gt;每年大约有 0.5-1% 的固态硬盘（SSD）故障。不可纠正的错误大约每年每块硬盘发生一次&lt;/li&gt;
&lt;li&gt;大约每 1,000 台机器中就有一台的 CPU 核心偶尔计算出错误的结果&lt;/li&gt;
&lt;li&gt;RAM 中的数据也可能被破坏，原因可能是宇宙射线等随机事件，或是永久性物理缺陷。此外，某些病态的内存访问模式可以高概率地翻转位。&lt;/li&gt;
&lt;li&gt;其他硬件组件如电源供应器、RAID 控制器和内存模块也会发生故障&lt;/li&gt;
&lt;li&gt;整个数据中心可能变得不可用（例如，由于停电或网络配置错误）或甚至被永久性破坏（例如火灾或洪水）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;软件故障往往是难以预料，而且因为是跨节点相关的，所以硬件故障往往可能造成更多的系统失效：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接受特定的错误输入，便导致所有应用服务器实例崩溃的 BUG。例如 2012 年 6 月 30 日的闰秒，由于 Linux 内核中的一个错误，许多应用同时挂掉了。&lt;/li&gt;
&lt;li&gt;失控进程会用尽一些共享资源，包括 CPU 时间、内存、磁盘空间或网络带宽。&lt;/li&gt;
&lt;li&gt;系统依赖的服务变慢，没有响应，或者开始返回错误的响应。&lt;/li&gt;
&lt;li&gt;级联故障，一个组件中的小故障触发另一个组件中的故障，进而触发更多的故障&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;运维配置错误是导致服务中断的首要原因，而硬件故障（服务器或网络）仅导致了 10-25% 的服务中断。&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%bc%b8%e7%bc%a9%e6%80%a7%e5%8e%9f%e5%88%99" 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;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" 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;跟踪问题的原因，例如系统故障或性能下降。&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;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;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;li&gt;提供良好的文档和易于理解的操作模型（“如果做 X，会发生 Y”）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提供良好的默认行为，但需要时也允许管理员自由覆盖默认值&lt;/strong&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;blockquote&gt;&lt;p&gt;带有太强个人色彩的系统无法成功。当最初的设计完成并且相对稳定时，不同的人们以自己的方式进行测试，真正的考验才开始。
—— 高德纳&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;ch3 数据模型与查询语言
 &lt;div id="ch3-数据模型与查询语言" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch3-%e6%95%b0%e6%8d%ae%e6%a8%a1%e5%9e%8b%e4%b8%8e%e6%9f%a5%e8%af%a2%e8%af%ad%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;大多数应用程序是通过在一个数据模型之上层叠另一个数据模型来构建的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;作为应用开发者，你观察现实世界（其中有人、组织、商品、行动、资金流动、传感器等），并以对象或数据结构以及操作这些数据结构的 API 的形式对其进行建模。这些结构通常是针对你的应用特定的。&lt;/li&gt;
&lt;li&gt;当你想存储这些数据结构时，你会用通用数据模型来表达它们，比如 JSON 或 XML 文档、关系数据库中的表，或图中的顶点和边。这些数据模型是本章的主题。&lt;/li&gt;
&lt;li&gt;构建你的数据库软件的工程师决定了一种将该 JSON/关系/图数据表示为内存、磁盘或网络上的字节的方式。这种表现可能允许数据被查询、搜索、操作和以各种方式处理。我们将在[后续链接]中讨论这些存储引擎设计。&lt;/li&gt;
&lt;li&gt;在更低的层次上，硬件工程师已经找出了如何将字节以电流、光脉冲、磁场等形式表示。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;SQL &amp;amp; NOSQL
 &lt;div id="sql--nosql" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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--nosql" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;数据库能够在多个 CPU 核心和机器上并行执行声明式查询，而你无需担心如何实现该并行性。在手工编码的算法中，自行实现这种并行执行将是一项巨大的工作。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;关系模型&lt;/em&gt;，尽管已有半个世纪之久，仍然是许多应用程序的重要数据模型——特别是在数据仓库和商业分析中，关系星型或雪花型架构和SQL查询无处不在。然而，在其他领域，几种替代关系数据的模型也变得流行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;文档模型&lt;/em&gt; 针对数据以自包含的 JSON 文档形式出现，且文档之间的关系罕见的用例。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;图数据模型&lt;/em&gt; 则走向相反方向，针对任何事物都可能与一切相关的用例，查询可能需要跨多个跳点寻找感兴趣的数据（这可以通过在 Cypher、SPARQL 或 Datalog 中使用递归查询来表达）。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;dataframe&lt;/em&gt; 将关系数据概括为大量的列，从而在数据库和构成大部分机器学习、统计数据分析和科学计算基础的多维数组之间架起了一座桥梁。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数据库也趋向于通过添加对其他数据模型的支持来扩展到相邻领域：例如，关系数据库增加了对文档数据的支持，以 JSON 列的形式，文档数据库增加了类似关系的连接，对 SQL 中图数据的支持也在逐渐改进。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch4 存储和索引
 &lt;div id="ch4-存储和索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch4-%e5%ad%98%e5%82%a8%e5%92%8c%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="#%e6%95%a3%e5%88%97%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;键值存储与在大多数编程语言中可以找到的 &lt;em&gt;字典（dictionary）&lt;/em&gt; 类型非常相似，通常字典都是用 &lt;em&gt;散列映射（hash map）&lt;/em&gt; 或 &lt;em&gt;散列表（hash table）&lt;/em&gt; 实现的。&lt;/p&gt;
&lt;p&gt;一般来说，HASH索引的散列映射完全保留在内存中。而数据值可以使用比可用内存更多的空间，因为可以在硬盘上通过一次硬盘查找操作来加载所需部分。&lt;/p&gt;
&lt;p&gt;散列索引的缺陷：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原则上可以在硬盘上维护一个散列映射，不幸的是硬盘散列映射很难表现优秀。它需要大量的随机访问 I/O，而后者耗尽时想要再扩充是很昂贵的，并且需要很烦琐的逻辑去解决散列冲突&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;范围查询效率不高&lt;/strong&gt;。例如，你无法轻松扫描 kitty00000 和 kitty99999 之间的所有键 —— 你必须在散列映射中单独查找每个键&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;B树索引
 &lt;div id="b树索引" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#b%e6%a0%91%e7%b4%a2%e5%bc%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;B树索引在1970年就已经出现，并且广泛被行业接受和使用。
该部分内容大部分人较为熟悉，略。&lt;/p&gt;

&lt;h3 class="relative group"&gt;SStables &amp;amp; LSM tree
 &lt;div id="sstables--lsm-tree" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#sstables--lsm-tree" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;HASH索引中键值对的顺序并不重要，但我们可以要求键值对的序列按键排序。这个格式称为 排序字符串表（Sorted String Table），简称 SSTable。
与使用散列索引的日志段相比，SSTable 有几个大的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;即使文件大于可用内存，合并段的操作仍然是简单而高效的。这种方法就像归并排序算法中使用的方法一样，如 图 3-4 所示：你开始并排读取多个输入文件，查看每个文件中的第一个键，复制最低的键（根据排序顺序）到输出文件，不断重复此步骤，将产生一个新的合并段文件，而且它也是也按键排序的。



&lt;img src="https://lastdba.com/img/csdn/4af781ce48d4.png" alt="image.png" /&gt;&lt;/li&gt;
&lt;li&gt;为了在文件中找到一个特定的键，你不再需要在内存中保存所有键的索引。你仍然需要一个内存中的索引来告诉你一些键的偏移量，但它可以是稀疏的：每几千字节的段文件有一个键就足够了，因为几千字节可以很快地被扫描完。



&lt;img src="https://lastdba.com/img/csdn/6c279ab1a032.png" alt="image.png" /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用这些数据结构，你可以按任何顺序插入键，并按排序顺序读取它们。
现在我们可以让我们的存储引擎以如下方式工作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有新写入时，将其添加到内存中的平衡树数据结构（例如红黑树）。这个内存树有时被称为 内存表（memtable）。&lt;/li&gt;
&lt;li&gt;当内存表大于某个阈值（通常为几兆字节）时，将其作为 SSTable 文件写入硬盘。这可以高效地完成，因为树已经维护了按键排序的键值对。新的 SSTable 文件将成为数据库中最新的段。当该 SSTable 被写入硬盘时，新的写入可以在一个新的内存表实例上继续进行。&lt;/li&gt;
&lt;li&gt;收到读取请求时，首先尝试在内存表中找到对应的键，如果没有就在最近的硬盘段中寻找，如果还没有就在下一个较旧的段中继续寻找，以此类推。&lt;/li&gt;
&lt;li&gt;时不时地，在后台运行一个合并和压缩过程，以合并段文件并将已覆盖或已删除的值丢弃掉。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里描述的算法本质上是LevelDB和RocksDB这些键值存储引擎库所使用的技术，这些存储引擎被设计嵌入到其他应用程序中。在 Cassandra和HBase中也使用了类似的存储引擎，而且&lt;strong&gt;他们都受到了Google的Bigtable 论文（引入了术语 SSTable 和 memtable ）的启发&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%86%85%e5%ad%98%e6%95%b0%e6%8d%ae%e5%ba%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;内存数据库：
随着 RAM 变得更便宜，每GB成本比RAM低的论据被侵蚀了。许多数据集不是那么大，所以将它们全部保存在内存中是非常可行的，包括可能分布在多个机器上。这导致了内存数据库的发展。
在重新启动计算机时丢失的数据是可以接受的。也可以通过特殊的硬件（例如电池供电的 RAM）来实现持久性，也可以将更改日志写入硬盘，还可以将定时快照写入硬盘或者将内存中的状态复制到其他机器上。&lt;/p&gt;
&lt;p&gt;典型的内存数据库Redis通过异步写入硬盘提供了较弱的持久性。其他内存数据库还有Memcached、VoltDB、MemSQL、Oracle TimesTen、RAM Cloud。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反直觉的是，内存数据库的性能优势并不是因为它们不需要从硬盘读取，相反，它们更快的原因在于省去了将内存数据结构编码为硬盘数据结构的开销&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;物化视图与OLAP
 &lt;div id="物化视图与olap" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e5%8c%96%e8%a7%86%e5%9b%be%e4%b8%8eolap" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如 SQL 中的 COUNT、SUM、AVG、MIN 或 MAX。如果相同的聚合被许多不同的查询使用，那么每次都通过原始数据来处理可能太浪费了。为什么不将一些查询使用最频繁的计数或总和缓存起来？创建这种缓存的一种方式是物化视图（Materialized View）。&lt;/p&gt;
&lt;p&gt;当底层数据发生变化时，物化视图需要更新，因为它是数据的非规范化副本。&lt;strong&gt;数据库可以自动完成该操作，但是这样的更新使得写入成本更高，这就是在 OLTP 数据库中不经常使用物化视图的原因&lt;/strong&gt;。&lt;strong&gt;在读取繁重的数据仓库中，它们可能更有意义，因为数仓不会有小而多的更新&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;物化数据立方体的优点是可以让某些查询变得非常快，因为它们已经被有效地预先计算了。例如，如果你想知道每个商店的总销售额，则只需查看合适维度的总计，而无需扫描数百万行的原始数据。&lt;/p&gt;
&lt;p&gt;数据立方体的缺点是不具有查询原始数据的灵活性。例如，没有办法计算有多少比例的销售来自成本超过 100 美元的项目，因为价格不是其中的一个维度。因此，大多数数据仓库试图保留尽可能多的原始数据，并将聚合数据（如数据立方体）仅用作某些查询的性能提升手段。&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%97%e5%bc%8f%e5%ad%98%e5%82%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;列式存储背后的想法很简单：不要将所有来自一行的值存储在一起，而是将来自每一列的所有值存储在一起。列式存储在关系数据模型中是最容易理解的，但它同样适用于非关系数据。例如，Parquet是一种列式存储格式，支持基于 Google 的 Dremel 的文档数据模型。
这些优化（列压缩、排序等等）在数据仓库中是有意义的，因为其负载主要由分析人员运行的大型只读查询组成。列式存储、压缩和排序都有助于更快地读取这些查询。然而，他们的缺点是写入更加困难。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch5 编码和演化
 &lt;div id="ch5-编码和演化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch5-%e7%bc%96%e7%a0%81%e5%92%8c%e6%bc%94%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;REST与RPC
 &lt;div id="rest与rpc" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rest%e4%b8%8erpc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;服务器通过网络公开 API，并且客户端可以连接到服务器以向该 API 发出请求。服务器公开的 API 被称为服务。通过 GET 请求下载，通过 POST 请求提交数据到服务器。
当服务使用 HTTP 作为底层通信协议时，可称之为 Web 服务。有两种流行的 Web 服务方法：REST 和 SOAP。REST 不是一个协议，而是一个基于 HTTP 原则的设计哲学，根据 REST 原则设计的 API 称为 RESTful。
远程过程调用（RPC）与本地函数调用非常不同&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;REST 似乎是公共 API 的主要风格，RPC 框架的主要重点在于同一组织拥有的服务之间的请求，通常在同一数据中心内。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch6 复制
 &lt;div id="ch6-复制" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch6-%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;复制日志、failover、单主模式，内容比较简单，略。&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%9a%e4%b8%bb%e5%a4%8d%e5%88%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;多主复制在许多数据库中都属于改装的功能，所以常常存在微妙的配置缺陷，且经常与其他数据库功能之间出现意外的反应。比如自增主键、触发器、完整性约束等都可能会有麻烦。因此，&lt;strong&gt;多主复制往往被认为是危险的领域，应尽可能避免&lt;/strong&gt;。
但是多主复制确实有一定的优势，例如分散写入IO、容灾、异地多中心减少网络开销（本地写入）等等。
写冲突：
多主复制的最大问题是可能发生写冲突，解决起来也比较棘手。
原则上，可以使冲突检测同步 - 即等待写入被复制到所有副本，然后再告诉用户写入成功。但是这可能违背了多主的初衷，&lt;strong&gt;如果你想要同步冲突检测，那么可能不如直接使用单主复制&lt;/strong&gt;。
解决多主写冲突：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免冲突。例如应用程序控制用户仅编辑自己的数据。&lt;/li&gt;
&lt;li&gt;收敛一致
&lt;ul&gt;
&lt;li&gt;最后写入胜利（LWW, last write wins）。按时间戳写入，可能会有数据丢失。&lt;/li&gt;
&lt;li&gt;优先级写入。高优先级的写入，可能会有数据丢失。&lt;/li&gt;
&lt;li&gt;额外的代码。保持冲突信息，编写额外的冲突解决代码&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实时协作编辑应用程序允许多个人同时编辑文档，如Etherpad、Google Docs有许多成熟案例。&lt;strong&gt;数据库在多主写入方面还很年轻&lt;/strong&gt;。
数据库多主写入冲突大部分情况都在应用层面解决或避免，以下比较成熟的写入冲突的研究供参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无冲突复制数据类型（Conflict-free replicated datatypes，CRDT）是可以由多个用户同时编辑的集合、映射、有序列表、计数器等一系列数据结构，它们以合理的方式自动解决冲突。一些 CRDT 已经在 Riak 2.0 中实现。&lt;/li&gt;
&lt;li&gt;可合并的持久数据结构（Mergeable persistent data structures）显式跟踪历史记录，类似于 Git 版本控制系统，并使用三向合并功能（而 CRDT 使用双向合并）。&lt;/li&gt;
&lt;li&gt;操作转换（operational transformation）是 Etherpad 和 Google Docs 等协同编辑应用背后的冲突解决算法。它是专为有序列表的并发编辑而设计的，例如构成文本文档的字符列表。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;ch7 分区
 &lt;div id="ch7-分区" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch7-%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e8%8c%83%e5%9b%b4%e5%88%86%e5%8c%ba%e5%92%8chash%e5%88%86%e5%8c%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;范围分区分区的缺点是某些特定的访问模式会导致热点。如果主键是时间戳，则分区对应于时间范围，写入操作都会转到同一个分区（即今天的分区），这样分区可能会因写入而过载，而其他分区则处于空闲状态。
可以使用除了时间戳以外的其他东西作为主键的第一个部分以打散热点，缺点在于范围查询不会受益。
hash分区可以缓解偏斜和热点的风险。出于分区的目的，散列函数不需要多么强壮的加密算法。
hash分区的缺陷是，通过使用键散列进行分区，我们失去了键范围分区的一个很好的属性：高效执行范围查询的能力。
哈希分区可以帮助减少热点。但是，它不能完全避免。例如，在社交媒体网站上，一个拥有数百万追随者的名人用户在做某事时可能会引发一场风暴。这个事件可能导致同一个键的大量写入（键可能是名人的用户 ID，或者人们正在评论的动作的 ID。此时哈希策略不起作用，因为两个相同 ID 的哈希值仍然是相同的。
&lt;strong&gt;如果一个主键很热，一个简单的解决方法是在主键的开始或结尾添加一个随机数&lt;/strong&gt;。只要一个两位数的十进制随机数就可以将主键分散为 100 种不同的主键，从而存储在不同的分区中。总之还是打散热点，并且要考虑范围查询等副作用。&lt;/p&gt;

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

&lt;h3 class="relative group"&gt;ACID、BASE
 &lt;div id="acidbase" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#acidbase" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ACID其实是一个很古老的定义，由于后期发现了很多的“异象”，所以一个系统说自己保证ACID实际上他说不清自己保证了什么。
ACID不管怎样还是深入人心的，他代表了事务的最基本的原则。相反的，不符合 ACID标准的系统有时被称为 BASE，他代表基本可用性（Basically Available），软状态（Soft State）和 最终一致性（Eventual consistency）。BASE是NOSQL常提及的概念。
BASE的定义比ACID还要模糊，一个简单、易理解、容易记忆的BASE理论：BASE（英文含义为碱）是反ACID（英文含义为酸）的概念。
可以简单地这么理解：&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;关系型数据库&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;ACID&lt;/td&gt;
 &lt;td&gt;BASE&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;SQL&lt;/td&gt;
 &lt;td&gt;NOSQL&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;ACID中的原子性和隔离性比较好理解。
一致性概念实际上很模糊，而且看起来跟数据库关系不大。书中一段引用非常经典：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Joe Hellerstein指出，在 Härder 与 Reuter 的论文中，“ACID 中的 C” 是被 “扔进去凑缩写单词的”，而且那时候大家都不怎么在乎一致性&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;而隔离性的定义非常模糊，可串行话的工业化的实践也停滞不前。
事务的隔离性可谓“一团浆糊”，但是可串行化是灵丹妙药为什么没人用呢？
参考这篇文章&lt;a href="https://blog.csdn.net/qq_40687433/article/details/131333588?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522B6B398A0-4A52-4F1D-A9F4-A4C01D200F72%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=B6B398A0-4A52-4F1D-A9F4-A4C01D200F72&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-5-131333588-null-null.nonecase&amp;amp;utm_term=%E9%9A%94%E7%A6%BB&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;事务的历史与SSI&lt;/a&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;li&gt;成本过高。不仅是数据库串行化隔离级别开发成本高，应用对可串行化也需要适应成本。光是理解这部分复杂的理论就不是一件容易的事；&lt;/li&gt;
&lt;li&gt;高级别的隔离会丢失一些性能。大量的改造工作可能是吃力不讨好的，应用需要在“高并发”和“无异常现象”间做抉择；&lt;/li&gt;
&lt;li&gt;业务基于机制开发，而不是规则开发。业务多少有点适应弱隔离级别的异常现象，特别是RC 。&lt;/li&gt;
&lt;/ul&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="#%e6%82%b2%e8%a7%82%e5%92%8c%e4%b9%90%e8%a7%82%e4%ba%8b%e5%8a%a1%e6%a8%a1%e5%9e%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;两阶段锁是一种所谓的悲观并发控制机制（pessimistic）：它是基于这样的原则：如果有事情可能出错（如另一个事务持有锁），最好等到情况安全后再做事情。这就像互斥，用于保护多线程编程中的数据结构。
从某种意义上说，串行执行可以称为悲观到了极致：在事务持续期间，每个事务对整个数据库（或数据库的一个分区）具有排它锁，作为对悲观的补偿，我们让每笔事务执行得非常快，所以只需要短时间持有“锁”。
相比之下，&lt;strong&gt;串行化快照隔离是一种乐观（optimistic）的并发控制技术&lt;/strong&gt;。在这种情况下，乐观意味着，如果存在潜在的危险也不阻止事务，而是继续执行事务，希望一切都会好起来。当一个事务想要提交时，数据库检查是否有什么不好的事情发生（即违反隔离原则）；如果是的话，事务将被中止，并且必须重试。只有可串行化的事务才被允许提交。&lt;strong&gt;如果存在很多争用（contention，即很多事务试图访问相同的对象），则表现不佳，因为这会导致很大一部分事务需要中止&lt;/strong&gt;。如果系统已经接近最大吞吐量，来自重试事务的额外负载可能会使性能变差。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch9 分布式系统
 &lt;div id="ch9-分布式系统" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch9-%e5%88%86%e5%b8%83%e5%bc%8f%e7%b3%bb%e7%bb%9f" 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%97%b6%e9%92%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;时钟在分布式系统中十分关键，它可能会直接影响事务的可见性/隔离性/正确性。
实际上准确的读取时间点是没有意义的（从量子理论上看就没有绝对的时间点的概念，实际情况要更复杂）。 Spanner 中的 Google TrueTime API 地报告了本地时钟的置信区间。置信区间会报告一个极短且可信的时间范围，而不是一个时间点。
例如，如果你有两个置信区间，每个置信区间包含最早和最晚可能的时间戳（$A = [A_{earliest}, A_{latest}]$，$B=[B_{earliest}, B_{latest}]$），这两个区间不重叠（即：$A_{earliest} &amp;lt;A_{latest} &amp;lt;B_{earliest} &amp;lt;B_{latest}$）的话，那么 B 肯定发生在 A 之后 —— 这是毫无疑问的。只有当区间重叠时，我们才不确定 A 和 B 发生的顺序。
为了确保事务时间戳反映因果关系，在提交读写事务之前，Spanner 在提交读写事务时，会故意等待置信区间长度的时间。Spanner 为了保持尽可能小的时钟不确定性，Google 在每个数据中心都部署了一个 GPS 接收器或原子钟，这允许时钟同步到大约 7 毫秒以内。
**逻辑时钟（logic clock）**是基于递增计数器而不是振荡石英晶体。逻辑时钟仅测量事件的相对顺序。&lt;/p&gt;
&lt;p&gt;实时可能不存在。响应优先级高于一切。对于大多数服务器端数据处理系统来说，实时保证是不经济或不合适的。因此，这些系统必须承受在非实时环境中运行的暂停和时钟不稳定性。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch10 一致性与共识
 &lt;div id="ch10-一致性与共识" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch10-%e4%b8%80%e8%87%b4%e6%80%a7%e4%b8%8e%e5%85%b1%e8%af%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;CAP
 &lt;div id="cap" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cap" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;CAP 定理的正式定义仅限于很狭隘的范围，它只考虑了一个一致性模型（即线性一致性）和一种故障（网络分区，或活跃但彼此断开的节点）。它没有讨论任何关于网络延迟，死亡节点或其他权衡的事。因此，尽管 CAP 在历史上有一些影响力，但对于设计系统而言并没有实际价值。&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%b8%83%e5%bc%8f%e4%ba%8b%e5%8a%a1%e5%92%8c%e5%85%b1%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;迄今为止所讨论的所有共识协议，在内部都以某种形式使用一个领导者，但它们并不能保证领导者是独一无二的。相反，它们可以做出更弱的保证：协议定义了一个纪元编号（epoch number，在 Paxos 中被称为投票编号，即 ballot number，在视图戳复制中被称为视图编号，即 view number，以及在 Raft 中被为任期号码，即 term number），并确保在每个时代中，领导者都是唯一的。
每次当现任领导被认为挂掉的时候，节点间就会开始一场投票，以选出一个新领导。这次选举被赋予一个递增的纪元编号，因此纪元编号是全序且单调递增的。如果两个不同的时代的领导者之间出现冲突（也许是因为前任领导者实际上并未死亡），那么带有更高纪元编号的领导说了算。
设计能健壮应对不可靠网络的算法仍然是一个开放的研究问题。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch11 批处理
 &lt;div id="ch11-批处理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch11-%e6%89%b9%e5%a4%84%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;服务（在线系统）
服务等待客户的请求或指令到达。每收到一个，服务会试图尽快处理它，并发回一个响应。响应时间通常是服务性能的主要衡量指标，可用性通常非常重要（如果客户端无法访问服务，用户可能会收到错误消息）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;批处理系统（离线系统）
一个批处理系统有大量的输入数据，跑一个作业（job） 来处理它，并生成一些输出数据，这往往需要一段时间（从几分钟到几天），所以通常不会有用户等待作业完成。相反，批量作业通常会定期运行（例如，每天一次）。批处理作业的主要性能衡量标准通常是吞吐量（处理特定大小的输入所需的时间）。本章中讨论的就是批处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流处理系统（准实时系统）
流处理介于在线和离线（批处理）之间，所以有时候被称为准实时（near-real-time）或准在线（nearline）处理。像批处理系统一样，流处理消费输入并产生输出（并不需要响应请求）。但是，流式作业在事件发生后不久就会对事件进行操作，而批处理作业则需等待固定的一组输入数据。这种差异使流处理系统比起批处理系统具有更低的延迟。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2004 年发布的批处理算法 Map-Reduce（可能被过分热情地）被称为 “造就 Google 大规模可伸缩性的算法”，MapReduce 是一个相当低级别的编程模型。&lt;/p&gt;

&lt;h3 class="relative group"&gt;MapReduce和分布式文件系统
 &lt;div id="mapreduce和分布式文件系统" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mapreduce%e5%92%8c%e5%88%86%e5%b8%83%e5%bc%8f%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;与关系数据库的查询优化器相比，即使 Unix 工具非常简单，但仍然非常有用。
Unix 工具的最大局限在于它们只能在一台机器上运行 —— 而 Hadoop 这样的工具即应运而生
MapReduce 有点像 Unix 工具，但分布在数千台机器上。像 Unix 工具一样，它相当简单粗暴，但令人惊异地管用。
MapReduce 作业在分布式文件系统上读写文件。在 Hadoop 的 MapReduce 实现中，该文件系统被称为 HDFS（Hadoop 分布式文件系统），一个 Google 文件系统（GFS）的开源实现。
除 HDFS 外，还有各种其他分布式文件系统，如 GlusterFS 和 Quantcast File System（QFS）。诸如 Amazon S3、Azure Blob 存储和 OpenStack Swift等对象存储服务在很多方面都是相似的&lt;/p&gt;
&lt;p&gt;要创建 MapReduce 作业，你需要实现两个回调函数，Mapper 和 Reducer，其行为如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mapper
Mapper 会在每条输入记录上调用一次，其工作是从输入记录中提取键值。对于每个输入，它可以生成任意数量的键值对（包括 None）。它不会保留从一个输入记录到下一个记录的任何状态，因此每个记录都是独立处理的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reducer
MapReduce 框架拉取由 Mapper 生成的键值对，收集属于同一个键的所有值，并在这组值上迭代调用 Reducer。Reducer 可以产生输出记录（例如相同 URL 的出现次数）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 MapReduce 编程模型，能将计算的物理网络通信层面（从正确的机器获取数据）从应用逻辑中剥离出来（获取数据后执行处理）。这种分离与数据库的典型用法形成了鲜明对比，从数据库中获取数据的请求经常出现在应用代码内部。由于 MapReduce 处理了所有的网络通信，因此它也避免了让应用代码去担心部分故障，例如另一个节点的崩溃：MapReduce 在不影响应用逻辑的情况下能透明地重试失败的任务。
“把相关数据放在一起” 的另一种常见模式是，按某个键对记录分组（如 SQL 中的 GROUP BY 子句）。使用 MapReduce 实现这种分组操作的最简单方法是设置 Mapper，以便它们生成的键值对使用所需的分组键。然后分区和排序过程将所有具有相同分区键的记录导向同一个 Reducer。&lt;/p&gt;

&lt;h3 class="relative group"&gt;Hadoop与分布式数据库的对比
 &lt;div id="hadoop与分布式数据库的对比" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hadoop%e4%b8%8e%e5%88%86%e5%b8%83%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e5%af%b9%e6%af%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;正如我们所看到的，Hadoop 有点像 Unix 的分布式版本，其中 HDFS 是文件系统，而 MapReduce 是 Unix 进程的怪异实现（总是在 Map 阶段和 Reduce 阶段运行 &lt;code&gt;sort&lt;/code&gt; 工具）。我们了解了如何在这些原语的基础上实现各种连接和分组操作。&lt;/p&gt;
&lt;p&gt;当 MapReduce 论文发表时，它从某种意义上来说 —— 并不新鲜。我们在前几节中讨论的所有处理和并行连接算法已经在十多年前所谓的大规模并行处理（MPP，massively parallel processing）数据库中实现了。比如 Gamma database machine、Teradata 和 Tandem NonStop SQL 就是这方面的先驱。&lt;/p&gt;
&lt;p&gt;最大的区别是，MPP 数据库专注于在一组机器上并行执行分析 SQL 查询，而 MapReduce 和分布式文件系统的组合则更像是一个可以运行任意程序的通用操作系统。&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%84%e7%90%86%e6%a8%a1%e5%9e%8b%e7%9a%84%e5%a4%9a%e6%a0%b7%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;只有两种处理模型，SQL 和 MapReduce，还不够，需要更多不同的模型！而且由于 Hadoop 平台的开放性，实施一整套方法是可行的，而这在单体 MPP 数据库的范畴内是不可能的。
传统上，MPP 数据库满足了商业智能分析和业务报表的需求，但这只是许多使用批处理的领域之一。
自 MapReduce 开始流行的这几年以来，分布式批处理的执行引擎已经很成熟了。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch12 流处理
 &lt;div id="ch12-流处理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch12-%e6%b5%81%e5%a4%84%e7%90%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;事件溯源
 &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%e4%bb%b6%e6%ba%af%e6%ba%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;事件溯源是一种强大的数据建模技术：从应用的角度来看，将用户的行为记录为不可变的事件更有意义，而不是在可变数据库中记录这些行为的影响。事件溯源类似于编年史（chronicle）数据模型
与变更数据捕获类似，事件溯源涉及到 将所有对应用状态的变更存储为变更事件日志。
使用事件溯源的应用需要拉取事件日志（表示写系统的数据），并将其转换为适合向用户显示的应用状态。从事件日志中派生出当前状态。&lt;/p&gt;

&lt;h2 class="relative group"&gt;ch13 数据系统的未来
 &lt;div id="ch13-数据系统的未来" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ch13-%e6%95%b0%e6%8d%ae%e7%b3%bb%e7%bb%9f%e7%9a%84%e6%9c%aa%e6%9d%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;lambda架构
 &lt;div id="lambda架构" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lambda%e6%9e%b6%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果批处理用于重新处理历史数据，而流处理用于处理最近的更新，那么如何将这两者结合起来？Lambda 架构是这方面的一个建议
Lambda 架构的核心思想是通过将不可变事件附加到不断增长的数据集来记录传入数据，这类似于事件溯源。
在 Lambda 方法中，流处理器消耗事件并快速生成对视图的近似更新；批处理器稍后将使用同一组事件并生成衍生视图的更正版本。&lt;/p&gt;
&lt;p&gt;Unix 发展出的管道和文件只是字节序列，而数据库则发展出了 SQL 和事务。
哪种方法更好？当然这取决于你想要的是什么。Unix 是 “简单的”，因为它是对硬件资源相当薄的包装；关系数据库是 “更简单” 的，因为一个简短的声明性查询可以利用很多强大的基础设施（查询优化、索引、连接方法、并发控制、复制等），而不需要查询的作者理解其实现细节。
我将 NoSQL 运动解释为，希望将类 Unix 的低级别抽象方法应用于分布式 OLTP 数据存储的领域。&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%ba%94%e7%94%a8%e4%bb%a3%e7%a0%81%e5%92%8c%e7%8a%b6%e6%80%81%e7%9a%84%e5%88%86%e7%a6%bb" 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;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%a4%e7%bb%99%e7%ae%97%e6%b3%95%e6%89%80%e5%b8%a6%e6%9d%a5%e7%9a%84%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;1.偏见与其实：例如在种族隔离地区中，一个人的邮政编码，甚至是他们的 IP 地址，都是很强的种族指示物。这样的话，相信一种算法可以以某种方式将有偏见的数据作为输入，并产生公平和公正的输出似乎是很荒谬的。然而这种观点似乎常常潜伏在数据驱动型决策的支持者中，这种态度被讽刺为 “在处理偏差上，机器学习与洗钱类似”（machine learning is like money laundering for bias）。预测性分析系统只是基于过去进行推断；如果过去是歧视性的，它们就会将这种歧视归纳为规律
2.责任与问责：自动决策引发了关于责任与问责的问题。如果一个人犯了错误，他可以被追责，受决定影响的人可以申诉。算法也会犯错误，但是如果它们出错，谁来负责？
3.隐私与监视：让我们做一个思想实验，尝试用 &lt;strong&gt;监视（surveillance）&lt;/strong&gt; 一词替换 &lt;strong&gt;数据（data）&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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;由于软件和数据对世界产生了如此巨大的影响，我们工程师们必须牢记，我们有责任为我们想要的那种世界而努力：一个尊重人，尊重人性的世界。我希望我们能够一起为实现这一目标而努力。&lt;/p&gt;
&lt;/blockquote&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案例：planning time超长问题分析</title><link>https://lastdba.com/2024/08/21/postgresql%E6%A1%88%E4%BE%8Bplanning-time%E8%B6%85%E9%95%BF%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/</link><pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/21/postgresql%E6%A1%88%E4%BE%8Bplanning-time%E8%B6%85%E9%95%BF%E9%97%AE%E9%A2%98%E5%88%86%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="#%e9%97%ae%e9%a2%98%e5%88%86%e6%9e%90%e6%a6%82%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;库总是OOM，分析到是执行计划生成有问题，planning time 1秒，planning shared hit 100w。一通分析，定位到是统计信息基表pg_statistic膨胀，由于会话首次SQL执行时的CatCacheMiss，导致backend访问并缓存了pg_statistic过多的死元组数据。应用连接总会启用新会话，多个backend的总内存过大从而导致OOM。&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%e5%88%86%e6%9e%90%e6%a6%82%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;库总是OOM，分析到是执行计划生成有问题，planning time 1秒，planning shared hit 100w。一通分析，定位到是统计信息基表pg_statistic膨胀，由于会话首次SQL执行时的CatCacheMiss，导致backend访问并缓存了pg_statistic过多的死元组数据。应用连接总会启用新会话，多个backend的总内存过大从而导致OOM。&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%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;某库反复OOM和重启。经过一通问题排查，发现会话连接数不多，但是每个会话的内存占用比较高，总内存超过内存cg限制导致OOM。
初步可以排除以下原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不是元数据过多的问题导致。对象过多（一般是分区数太多）会导致会话缓存过多的元数据。这个库的对象不算多&lt;/li&gt;
&lt;li&gt;不是sql执行计划问题。排序/hash可能使用过多内存。这个库不是这个场景，sql可以是一个顺序扫描。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在问题分析过程中发现，库里面执行任意一个简单sql执行时间很长，并且 Planning Buffers有约100w&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers,timing) &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; lzlinfo &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; 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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;02&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;71&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;011&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;012&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; Buffers: shared hit&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; lzlinfo (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;480&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;73&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;473&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;71&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;010&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;010&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; Buffers: shared hit&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; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1127312&lt;/span&gt; &lt;span style="color:#75715e"&gt;--异常planning shared hit
&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;947&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;038&lt;/span&gt; ms &lt;span style="color:#75715e"&gt;--异常planning time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Execution Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;035&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;8&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;再执行一次sql，planning time就正常了。&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%ae%9a%e4%bd%8d%e8%bf%87%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;打印执行计划的stat信息
 &lt;div id="打印执行计划的stat信息" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%93%e5%8d%b0%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e7%9a%84stat%e4%bf%a1%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;把会话的执行计划各阶段的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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; log_parser_stats &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; log_planner_stats &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; log_executor_stats &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&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-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;2024-08-13 10:02:33.936 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,85532,&lt;span style="color:#e6db74"&gt;&amp;#34;[local]&amp;#34;&lt;/span&gt;,66babe8c.14e1c,13,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-08-13 10:01:48 CST,4/713,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;PARSER STATISTICS&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0.000046 s user, 0.000046 s system, 0.000091 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! [0.001661 s user, 0.001661 s system total]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 4660 kB max resident size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [0/8] filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/36 [0/996] page faults/reclaims, 0 [0] swaps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [5/0] voluntary/involuntary context switches&amp;#34;&lt;/span&gt;,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;explain (analyze,buffers) select *,1 from lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2024-08-13 10:02:33.938 CST,&amp;#34;&lt;/span&gt;postgres&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;lzldb&lt;span style="color:#e6db74"&gt;&amp;#34;,85532,&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;,66babe8c.14e1c,14,&amp;#34;&lt;/span&gt;EXPLAIN&lt;span style="color:#e6db74"&gt;&amp;#34;,2024-08-13 10:01:48 CST,4/713,0,LOG,00000,&amp;#34;&lt;/span&gt;PARSE ANALYSIS STATISTICS&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0.001459 s user, 0.000000 s system, 0.001464 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.003146 s user, 0.001687 s system total&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;5972&lt;/span&gt; kB max resident size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/8&lt;span style="color:#f92672"&gt;]&lt;/span&gt; filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/325 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/1324&lt;span style="color:#f92672"&gt;]&lt;/span&gt; page faults/reclaims, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; swaps
&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;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; signals rcvd, 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;5/0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; voluntary/involuntary context switches&lt;span style="color:#e6db74"&gt;&amp;#34;,,,,,&amp;#34;&lt;/span&gt;explain &lt;span style="color:#f92672"&gt;(&lt;/span&gt;analyze,buffers&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; *,1 from lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-08-13 10:02:33.938 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,85532,&lt;span style="color:#e6db74"&gt;&amp;#34;[local]&amp;#34;&lt;/span&gt;,66babe8c.14e1c,15,&lt;span style="color:#e6db74"&gt;&amp;#34;EXPLAIN&amp;#34;&lt;/span&gt;,2024-08-13 10:01:48 CST,4/713,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;REWRITER STATISTICS&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0.000001 s user, 0.000000 s system, 0.000001 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! [0.003177 s user, 0.001687 s system total]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 5972 kB max resident size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [0/8] filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [0/1324] page faults/reclaims, 0 [0] swaps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [5/0] voluntary/involuntary context switches&amp;#34;&lt;/span&gt;,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;explain (analyze,buffers) select *,1 from lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2024-08-13 10:02:34.644 CST,&amp;#34;&lt;/span&gt;postgres&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;lzldb&lt;span style="color:#e6db74"&gt;&amp;#34;,85532,&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;,66babe8c.14e1c,16,&amp;#34;&lt;/span&gt;EXPLAIN&lt;span style="color:#e6db74"&gt;&amp;#34;,2024-08-13 10:01:48 CST,4/713,0,LOG,00000,&amp;#34;&lt;/span&gt;PLANNER STATISTICS&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0.539964 s user, 0.164083 s system, 0.705718 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.543248 s user, 0.165770 s system total&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;745072&lt;/span&gt; kB max resident size --异常点
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/8&lt;span style="color:#f92672"&gt;]&lt;/span&gt; filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/184803 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/186157&lt;span style="color:#f92672"&gt;]&lt;/span&gt; page faults/reclaims, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; swaps
&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;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; signals rcvd, 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;! 0/1 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;5/1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; voluntary/involuntary context switches&lt;span style="color:#e6db74"&gt;&amp;#34;,,,,,&amp;#34;&lt;/span&gt;explain &lt;span style="color:#f92672"&gt;(&lt;/span&gt;analyze,buffers&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; *,1 from lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-08-13 10:02:34.644 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,85532,&lt;span style="color:#e6db74"&gt;&amp;#34;[local]&amp;#34;&lt;/span&gt;,66babe8c.14e1c,17,&lt;span style="color:#e6db74"&gt;&amp;#34;EXPLAIN&amp;#34;&lt;/span&gt;,2024-08-13 10:01:48 CST,4/713,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;EXECUTOR STATISTICS&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0.540248 s user, 0.164170 s system, 0.706088 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! [0.543532 s user, 0.165857 s system total]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 745596 kB max resident size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/0 [0/8] filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/184898 [0/186252] page faults/reclaims, 0 [0] swaps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;! 0/1 [5/1] voluntary/involuntary context switches&amp;#34;&lt;/span&gt;,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;explain (analyze,buffers) select *,1 from lzlinfo
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;planner阶段内存使用率暴涨，elapsed time也暴涨。这部分信息可以定位到是整个planning阶段中的planner阶段有问题。其他可用信息不多。&lt;/p&gt;

&lt;h3 class="relative group"&gt;strace追踪
 &lt;div id="strace追踪" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#strace%e8%bf%bd%e8%b8%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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;strace -p &lt;span style="color:#ae81ff"&gt;76419&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;strace: Process &lt;span style="color:#ae81ff"&gt;76419&lt;/span&gt; attached
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epoll_wait(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, [&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;EPOLLIN, &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;u32&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15422552&lt;/span&gt;, u64&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15422552&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom(&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Q\0\0\0\262explain (analyze,buffers) s&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&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:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;179&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;xfed000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x100e000) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x100e000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x100e000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x100e000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1007000) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1007000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x1007000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mmap(&lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;270336&lt;/span&gt;, PROT_READ&lt;span style="color:#f92672"&gt;|&lt;/span&gt;PROT_WRITE, MAP_PRIVATE&lt;span style="color:#f92672"&gt;|&lt;/span&gt;MAP_ANONYMOUS, &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:#ae81ff"&gt;0&lt;/span&gt;x2b7806b0c000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;base/17076/16678&amp;#34;&lt;/span&gt;, O_RDWR) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek(&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &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;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;base/17076/46160&amp;#34;&lt;/span&gt;, O_RDWR) &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;lseek(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7667712&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;base/17076/46168&amp;#34;&lt;/span&gt;, O_RDWR) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek(&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;188416&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;base/17076/46170&amp;#34;&lt;/span&gt;, O_RDWR) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek(&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;188416&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mmap(&lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;528384&lt;/span&gt;, PROT_READ&lt;span style="color:#f92672"&gt;|&lt;/span&gt;PROT_WRITE, MAP_PRIVATE&lt;span style="color:#f92672"&gt;|&lt;/span&gt;MAP_ANONYMOUS, &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:#ae81ff"&gt;0&lt;/span&gt;x2b78c1b36000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x1007000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x102c000) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x102c000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x102c000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x102c000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1025000) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x1025000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk(&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;0&lt;/span&gt;x1025000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, SEEK_END) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7667712&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;pg_stat_tmp/pgss_query_texts.stat&amp;#34;&lt;/span&gt;, O_RDWR&lt;span style="color:#f92672"&gt;|&lt;/span&gt;O_CREAT, &lt;span style="color:#ae81ff"&gt;0600&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pwrite64(&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;explain (analyze,buffers) select&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;93934&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pwrite64(&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\0&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;94106&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;close&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;15&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;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\250\3\0\0\264B\0\0\10\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;936&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;936&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\250\3\0\0\264B\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;936&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;936&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\250\3\0\0\264B\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;936&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;936&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\250\3\0\0\264B\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;936&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;936&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\250\3\0\0\264B\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;936&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;936&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\10\1\0\0\264B\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;264&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;264&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\10\1\0\0\0\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;264&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;264&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\16\0\0\0H\0\0\0\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;72&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;72&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto(&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;T\0\0\0#\0\1QUERY PLAN\0\0\0\0\0\0\0\0\0\0\31\377\377\377\377&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;826&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&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;826&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom(&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;xd2b4e0, &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&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:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; EAGAIN (Resource temporarily unavailable)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epoll_wait(&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;虽然shared hit很多，但strace信息很少
strace显示会话只open了4个数据文件，通过fd和oid2name查到数据文件，分别是表、表的两个索引以及pathman_config：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;From database &lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filenode Table 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 style="color:#ae81ff"&gt;46170&lt;/span&gt; ix_name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;46168&lt;/span&gt; pk_lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;46160&lt;/span&gt; lzlinfo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16678&lt;/span&gt; pathman_config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这些对象都不大，看上去不像这些表（or索引）过大导致的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;perf
 &lt;div id="perf" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#perf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;（图不好贴自行脑补）
perf火焰图有40%的时间在&lt;code&gt;heap_hot_search_buffer&lt;/code&gt;堆栈上&lt;/p&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;code&gt;heap_hot_search_buffe&lt;/code&gt;函数为依据，经过多次gdb，打如下断点试着看看哪有问题：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;b relation_open
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b get_relation_info
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b RelationCacheInvalidateEntry 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b get_relname_relid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b AcceptInvalidationMessages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b RelationClearRelation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b pg_hint_plan_planner
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;b heap_hot_search_buffer&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;code&gt;heap_hot_search_buffer&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;Breakpoint 15, heap_hot_search_buffer &lt;span style="color:#f92672"&gt;(&lt;/span&gt;tid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;tid@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x2313c60, relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x2b2141663910, buffer&lt;span style="color:#f92672"&gt;=&lt;/span&gt;17045, snapshot&lt;span style="color:#f92672"&gt;=&lt;/span&gt;snapshot@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x228a058, heapTuple&lt;span style="color:#f92672"&gt;=&lt;/span&gt;heapTuple@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x23273d0, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; all_dead&lt;span style="color:#f92672"&gt;=&lt;/span&gt;all_dead@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x7ffce272e28f, first_call&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&lt;span style="color:#f92672"&gt;)&lt;/span&gt; at heapam.c:1503
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1503&lt;/span&gt; in heapam.c
&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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Breakpoint 15, heap_hot_search_buffer &lt;span style="color:#f92672"&gt;(&lt;/span&gt;tid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;tid@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x2313c60, relation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x2b2141663910, buffer&lt;span style="color:#f92672"&gt;=&lt;/span&gt;96708, snapshot&lt;span style="color:#f92672"&gt;=&lt;/span&gt;snapshot@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x228a058, heapTuple&lt;span style="color:#f92672"&gt;=&lt;/span&gt;heapTuple@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x23273d0, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; all_dead&lt;span style="color:#f92672"&gt;=&lt;/span&gt;all_dead@entry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0x7ffce272e28f, first_call&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&lt;span style="color:#f92672"&gt;)&lt;/span&gt; at heapam.c:1503
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1503&lt;/span&gt; in heapam.c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;heap_hot_search_buffer&lt;/code&gt;传入的绝大部分参数没有变，包括relation、heapTuple的地址，只有buffer参数在改变，说明应该在扫描同一个relation。&lt;br&gt;
&lt;code&gt;heapTuple&lt;/code&gt;中包含table 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-shell" data-lang="shell"&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 *heapTuple
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$46 &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; t_len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 968, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_self &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; ip_blkid &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; bi_hi &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bi_lo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7211&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; ip_posid &lt;span style="color:#f92672"&gt;=&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; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_tableOid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 2619, --这个比较有用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x2b2155fced00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;heap_hot_search_buffer&lt;/code&gt;传入的oid=2619，2619在pg_class中对应&lt;code&gt;pg_statistic&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; oid,relname &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; oid &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;2619&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; relname 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;2619&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_statistic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;找这个统计信息基表无可厚非，因为pg在生成可能的执行计划s时需要用到统计信息来估算代价。&lt;/p&gt;

&lt;h3 class="relative group"&gt;pg_statistic的膨胀
 &lt;div id="pg_statistic的膨胀" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_statistic%e7%9a%84%e8%86%a8%e8%83%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;定位到pg_statistic，那么看下pg_statistic表的情况&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;dt&lt;span style="color:#f92672"&gt;+&lt;/span&gt; pg_statistic
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; relations
&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;Owner&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Persistence &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; 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; pg_catalog &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_statistic &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; postgres &lt;span style="color:#f92672"&gt;|&lt;/span&gt; permanent &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1036&lt;/span&gt; MB &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:#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_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;pg_statistic&amp;#39;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2619&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; pg_statistic
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relnamespace &lt;span style="color:#f92672"&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;reltype &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12016&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reloftype &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;relowner &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;relam &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;relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2619&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reltablespace &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;relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;132481&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reltuples &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4655&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_statistic&lt;/code&gt;有1G，确实有些大了， 有132481块却只有4655行，这明显是有表膨胀了。但是即便有表膨胀，访问统计信息需要cache整个pg_statistic吗？逻辑上来说不需要，因为只需要访问对应表的统计信息就行了，实际上pg也是通过&lt;code&gt;pg_statistic&lt;/code&gt;的主键索引&lt;code&gt;pg_statistic_relid_att_inh_index&lt;/code&gt;来访问的。从下面的从堆栈中能看到传入的是&lt;code&gt;pg_statistic&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;bt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000086edbc &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; SearchCatCacheMiss (&lt;span style="color:#66d9ef"&gt;cache&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;cache&lt;/span&gt;&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;x226ba80, nkeys&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nkeys&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;, hashValue&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hashValue&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;853716409&lt;/span&gt;, hashIndex&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hashIndex&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;57&lt;/span&gt;, v1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v1&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;18767&lt;/span&gt;, v2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v2&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;1&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v3&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;, v4&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v4&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;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; catcache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1368&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x000000000086fa82 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; SearchCatCacheInternal (v4&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, v3&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;, v2&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;, v1&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;, nkeys&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;cache&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x226ba80) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; catcache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1299&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; SearchCatCache3 (&lt;span style="color:#66d9ef"&gt;cache&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x226ba80, v1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v1&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;18767&lt;/span&gt;, v2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v2&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;1&lt;/span&gt;, v3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;v3&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;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; catcache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1183&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;x0000000000880d70 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; SearchSysCache3 (cacheId&lt;span style="color:#f92672"&gt;=&lt;/span&gt;cacheId&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;58&lt;/span&gt;, key1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;key1&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;18767&lt;/span&gt;, key2&lt;span style="color:#f92672"&gt;=&lt;/span&gt;key2&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;1&lt;/span&gt;, key3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;key3&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;) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; syscache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1145&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;x0000000000874092 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; get_attavgwidth (relid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;relid&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;18767&lt;/span&gt;, attnum&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;at&lt;/span&gt; lsyscache.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2991&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;x00000000006a2d46 &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; set_rel_width (root&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&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;x2326600, rel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rel&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;x21e8418) &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; costsize.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;5516&lt;/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;relid=relid@entry=18767, attnum=1&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; ctid,starelid,staattnum &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_statistic &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; starelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;18767&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; starelid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; staattnum 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;132657&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;18767&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;132657&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;18767&lt;/span&gt; &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:#ae81ff"&gt;132657&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;18767&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:#ae81ff"&gt;132657&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;18767&lt;/span&gt; &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:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&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; (&lt;span style="color:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &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; (&lt;span style="color:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &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:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &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; (&lt;span style="color:#ae81ff"&gt;132658&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;18767&lt;/span&gt; &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:#75715e"&gt;--lzlinfo总共10个字段，每个字段对应一个staattnum&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可以看出，这些数据实际上只在2个块中。
看下通过复合主键索引访问&lt;code&gt;pg_statistic&lt;/code&gt;，结果发现哪怕在只有2个块，也要访问1s，shared hit高达100w（1141568）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers,timing,&lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; ctid,starelid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_statistic &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; starelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;18767&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; pg_statistic_relid_att_inh_index &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; pg_catalog.pg_statistic (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;41&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;103&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;23&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;105&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;416&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1035&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;723&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;10&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:#66d9ef"&gt;Output&lt;/span&gt;: ctid, starelid
&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: (pg_statistic.starelid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;18767&amp;#39;&lt;/span&gt;::oid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1141568&lt;/span&gt; &lt;span style="color:#75715e"&gt;--异常
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;102&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;1035&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;802&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;通过索引访问10条pg_statistic数据，shared hit有100w，跟SQL的100w planning shared hit差不多。（注意这里的 Planning Time很少，说明我们没有在生成执行计划阶段出问题）&lt;/p&gt;

&lt;h3 class="relative group"&gt;索引dead tuple
 &lt;div id="索引dead-tuple" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%95dead-tuple" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果vacuum没有真的“跑起来”，那么索引的dead tuple还是会指向死元组
参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/137368881?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172420012616800225589534%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172420012616800225589534&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-2-137368881-null-null.nonecase&amp;amp;utm_term=%E8%86%A8%E8%83%80&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;从很慢的唯一索引扫描到索引膨胀&lt;/a&gt;



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

&lt;h3 class="relative group"&gt;autovacuum未回收死元组
 &lt;div id="autovacuum未回收死元组" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#autovacuum%e6%9c%aa%e5%9b%9e%e6%94%b6%e6%ad%bb%e5%85%83%e7%bb%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;表膨胀这么大，autovacuum不应该回收吗？&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;select * from pg_stat_all_tables where relname=&amp;#39;pg_statistic&amp;#39;\gx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-[ RECORD 1 ]-------+------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relid | 2619
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;schemaname | pg_catalog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relname | pg_statistic
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;seq_scan | 1 	 --顺序访问pg_statistic极少
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;seq_tup_read | 4655
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;idx_scan | 28715508 --索引访问pg_statistic多
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;idx_tup_fetch | 25150245
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_tup_ins | 46
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_tup_upd | 1292143 --update很多
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_tup_del | 14
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_tup_hot_upd | 138448
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_live_tup | 4655
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_dead_tup | 1496776
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_mod_since_analyze | 1292203
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_ins_since_vacuum | 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;last_vacuum | [null]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;last_autovacuum | 2024-08-16 20:34:15.045022+08 --注意autovacuum的时间是一个最近的值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;last_analyze | [null]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;last_autoanalyze | [null]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vacuum_count | 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autovacuum_count | 144170
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;analyze_count | 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autoanalyze_count | 0&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_statistic&lt;/code&gt;上是autovacuum一直在跑，只不过进程有可能看不到，因为autovacuum没有跑什么，所以跑的比较快，跑完又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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show autovacuum_naptime ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; autovacuum_naptime 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1min&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;每间隔1分钟休息一次，日志中也是每隔1分钟打印一次autovacuum信息。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2024-08-16 21:05:15.267 CST,,,41080,,66bf4e87.a078,1,,2024-08-16 21:05:11 CST,27/166839,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic vacuum of table &amp;#34;&amp;#34;lzldb.pg_catalog.pg_statistic&amp;#34;&amp;#34;: index scans: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;pages: 0 removed, 132685 remain, 1 skipped due to pins, 0 skipped frozen
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;tuples: 0 removed, 1501745 remain, 1497090 are dead but not yet removable, oldest xmin: 119329380
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;buffer usage: 265443 hits, 0 misses, 0 dirtied
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;avg read rate: 0.000 MB/s, avg write rate: 0.000 MB/s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;system usage: CPU: user: 0.53 s, system: 0.17 s, elapsed: 3.38 s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WAL usage: 1 records, 0 full page images, 233 bytes&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-08-16 21:05:17.474 CST,,,41080,,66bf4e87.a078,2,,2024-08-16 21:05:11 CST,27/166844,136438968,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic analyze of table &amp;#34;&amp;#34;lzldb.public.lzlinfo&amp;#34;&amp;#34; system usage: CPU: user: 2.02 s, system: 0.00 s, elapsed: 2.08 s&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&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;&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;1497090 are dead but not yet removable&lt;/code&gt;虽然触发了autovacuum但是根本没有回收到死元组，1497090条死元组没有清理。
排查下库内是谁持有了&lt;code&gt;oldest xmin: 119329380&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; &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; 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 style="color:#75715e"&gt;-----------------+----------+-----------+--------+----------+-----------+--------+------------+--------+--------------+--------------+---------------------+------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; slotslotlostname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pgoutput &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;17076&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:#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;119329380&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;F9&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;105&lt;/span&gt;A4970 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;F9&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;105&lt;/span&gt;F8778 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; extended &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;slot的&lt;code&gt;catalog_xmin=119329380&lt;/code&gt;，与vacuum展示的&lt;code&gt;oldest xmin: 119329380&lt;/code&gt;一致。
&lt;code&gt;active=f&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="#%e4%bf%ae%e5%a4%8d%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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;slotslotlostname&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_drop_replication_slot 
&lt;/span&gt;&lt;/span&gt;&lt;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;手动vacuum或再等待1分钟autovacuum。
最后再开一个全新的会话测试一下恢复没有：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; psql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql (&lt;span style="color:#ae81ff"&gt;13&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;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;&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;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:#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;,buffers,timing) &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; lzlinfo &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; 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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;04&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;71&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;023&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;025&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; Buffers: shared hit&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; lzlinfo (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;3802&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;73&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;473&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;71&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;018&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;018&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; Buffers: shared hit&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; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2578&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;9&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;605&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;098&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;耗时从1s下降到10ms，Planning shared hit从100w下降到2k，问题基本解决。&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%a1%88%e4%be%8b%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;复制链路挂掉，复制槽未及时清理，导致pg_statistic统计信息基表膨胀，导致每个backend在首次加载统计信息时都非常缓慢且读取多余的page到本地缓存，导致每个backend的缓存都大于正常水平（2g左右），多个backend导致最后的OOM。
其实问题很简单，只是过程比较曲折···简言之：基表pg_statistic膨胀导致执行计划生成阶段访问数据过大。元数据基表膨胀其实还有其他棘手的问题，有缘再见了。&lt;/p&gt;</content:encoded></item><item><title>ogg搭建oracle-pg同步——实操步骤</title><link>https://lastdba.com/2024/08/13/ogg%E6%90%AD%E5%BB%BAoracle-pg%E5%90%8C%E6%AD%A5%E5%AE%9E%E6%93%8D%E6%AD%A5%E9%AA%A4/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/ogg%E6%90%AD%E5%BB%BAoracle-pg%E5%90%8C%E6%AD%A5%E5%AE%9E%E6%93%8D%E6%AD%A5%E9%AA%A4/</guid><description>&lt;p&gt;​&lt;/p&gt;
&lt;p&gt;源库：  oracle(11.2.0.4) 192.168.10.141&lt;/p&gt;
&lt;p&gt;目标库：pgsql(10.12)     192.168.10.128&lt;/p&gt;
&lt;p&gt;ogg软件版本:(19.1.0.0.4)&lt;/p&gt;
&lt;p&gt;ogg软件下载：Oracle GoldenGate Downloads&lt;/p&gt;
&lt;p&gt;glibc问题处理：https://www.cnblogs.com/hxlasky/p/16779047.html&lt;/p&gt;</description><content:encoded>&lt;p&gt;​&lt;/p&gt;
&lt;p&gt;源库：  oracle(11.2.0.4) 192.168.10.141&lt;/p&gt;
&lt;p&gt;目标库：pgsql(10.12)     192.168.10.128&lt;/p&gt;
&lt;p&gt;ogg软件版本:(19.1.0.0.4)&lt;/p&gt;
&lt;p&gt;ogg软件下载：Oracle GoldenGate Downloads&lt;/p&gt;
&lt;p&gt;glibc问题处理：https://www.cnblogs.com/hxlasky/p/16779047.html&lt;/p&gt;
&lt;p&gt;1.在源端和目标端安装ogg软件&lt;/p&gt;
&lt;p&gt;源端：&lt;/p&gt;
&lt;p&gt;一、配置相应文件：oggcore.rsp&lt;/p&gt;
&lt;p&gt;oracle.install.responseFileVersion=/home/oracle/oggcore.rsp&lt;/p&gt;
&lt;p&gt;INSTALL_OPTION=ORA11g&lt;/p&gt;
&lt;p&gt;SOFTWARE_LOCATION=/oracle/ogg&lt;/p&gt;
&lt;p&gt;START_MANAGER=false&lt;/p&gt;
&lt;p&gt;MANAGER_PORT=7809&lt;/p&gt;
&lt;p&gt;DATABASE_LOCATION=/oracle/db/11.2.0.4&lt;/p&gt;
&lt;p&gt;INVENTORY_LOCATION=/oracle/oraInventory&lt;/p&gt;
&lt;p&gt;UNIX_GROUP_NAME=oinstall&lt;/p&gt;
&lt;p&gt;二、静默安装OGG&lt;/p&gt;
&lt;p&gt;./runInstaller -silent -nowait -responseFile /home/oracle/oggcore.rsp&lt;/p&gt;
&lt;p&gt;oracle@szgtsp431-or@ecsdb&amp;gt;./runInstaller -silent -nowait -responseFile /home/oracle/oggcore.rsp&lt;/p&gt;
&lt;p&gt;Starting Oracle Universal Installer&amp;hellip;&lt;/p&gt;
&lt;p&gt;Checking Temp space: must be greater than 120 MB.   Actual 32405 MB    Passed&lt;/p&gt;
&lt;p&gt;Checking swap space: must be greater than 150 MB.   Actual 2048 MB    Passed&lt;/p&gt;
&lt;p&gt;Preparing to launch Oracle Universal Installer from /tmp/OraInstall2020-08-14_08-57-27AM. Please wait &amp;hellip;oracle@szgtsp431-or@ecsdb&amp;gt;You can find the log of this install session at:&lt;/p&gt;
&lt;p&gt; /oracle/oraInventory/logs/installActions2020-08-14_08-57-27AM.log&lt;/p&gt;
&lt;p&gt;Successfully Setup Software.&lt;/p&gt;
&lt;p&gt;The installation of Oracle GoldenGate Core was successful.&lt;/p&gt;
&lt;p&gt;Please check &amp;lsquo;/oracle/oraInventory/logs/silentInstall2020-08-14_08-57-27AM.log&amp;rsquo; for more details.&lt;/p&gt;
&lt;p&gt;2.修改数据库为归档模式&lt;/p&gt;
&lt;p&gt;oracle@szgtsp431-or@ecsdb&amp;gt;sqlplus / as sysdba&lt;/p&gt;
&lt;p&gt;SQL*Plus: Release 11.2.0.4.0 Production on Fri Aug 14 09:06:34 2020&lt;/p&gt;
&lt;p&gt;Copyright (c) 1982, 2013, Oracle.  All rights reserved.&lt;/p&gt;
&lt;p&gt;Connected to:&lt;/p&gt;
&lt;p&gt;Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production&lt;/p&gt;
&lt;p&gt;With the Partitioning, OLAP, Data Mining and Real Application Testing options&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; archive log list;&lt;/p&gt;
&lt;p&gt;Database log mode              Archive Mode&lt;/p&gt;
&lt;p&gt;Automatic archival             Enabled&lt;/p&gt;
&lt;p&gt;Archive destination            /oracle/oradata/archivelog&lt;/p&gt;
&lt;p&gt;Oldest online log sequence     19&lt;/p&gt;
&lt;p&gt;Next log sequence to archive   21&lt;/p&gt;
&lt;p&gt;Current log sequence           21&lt;/p&gt;
&lt;p&gt;3.开启数据库的强制日志和最小附加日志&lt;/p&gt;
&lt;p&gt;alter database force logging;&lt;/p&gt;
&lt;p&gt;alter database add supplemental log data;&lt;/p&gt;
&lt;p&gt;alter system switch logfile;&lt;/p&gt;
&lt;p&gt;确认是否开启了强制日志和最小附加日志&lt;/p&gt;
&lt;p&gt;select force_logging,supplemental_log_data_min from v$database;&lt;/p&gt;
&lt;p&gt;4.修改enable_goldengate_replication参数&lt;/p&gt;
&lt;p&gt;alter system set enable_goldengate_replication=true scope=both;&lt;/p&gt;
&lt;p&gt;若为集群，所有节点都要修改:&lt;/p&gt;
&lt;p&gt;alter system set enable_goldengate_replication=true scope=both sid=&amp;rsquo;*&amp;rsquo;;&lt;/p&gt;
&lt;p&gt;5.创建ogg用户和ogg用户表空间并授权&lt;/p&gt;
&lt;p&gt;create tablespace tbs_ogg datafile &amp;lsquo;/oracle/oradata/datafile/tbs_ogg01.dbf&amp;rsquo; size 100M;&lt;/p&gt;
&lt;p&gt;create user goldengate identified by 123456 default tablespace tbs_ogg temporary tablespace temp;&lt;/p&gt;
&lt;p&gt;grant create session,alter session to goldengate;&lt;/p&gt;
&lt;p&gt;grant alter system to goldengate;&lt;/p&gt;
&lt;p&gt;grant resource to goldengate;&lt;/p&gt;
&lt;p&gt;grant connect to goldengate;&lt;/p&gt;
&lt;p&gt;grant select any dictionary to goldengate;&lt;/p&gt;
&lt;p&gt;grant flashback any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant select any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant select any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant insert any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant update any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant delete any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant select on dba_clusters to goldengate;&lt;/p&gt;
&lt;p&gt;grant execute on dbms_flashback to goldengate;&lt;/p&gt;
&lt;p&gt;grant create table to goldengate;&lt;/p&gt;
&lt;p&gt;grant create sequence to goldengate;&lt;/p&gt;
&lt;p&gt;grant alter any table to goldengate;&lt;/p&gt;
&lt;p&gt;grant dba to goldengate;&lt;/p&gt;
&lt;p&gt;grant lock any table to goldengate;&lt;/p&gt;
&lt;p&gt;6.开启表级附件日志&lt;/p&gt;
&lt;p&gt;要同步某个schema的表数据或者多个schema的数据，需要对表开启附加日志&lt;/p&gt;
&lt;p&gt;检查附件日志：&lt;/p&gt;
&lt;p&gt;SELECT&lt;/p&gt;
&lt;p&gt;owner,&lt;/p&gt;
&lt;p&gt;table_name,&lt;/p&gt;
&lt;p&gt;log_group_name,&lt;/p&gt;
&lt;p&gt;log_group_type,&lt;/p&gt;
&lt;p&gt;decode( always, &amp;lsquo;ALWAYS&amp;rsquo;, &amp;lsquo;Unconditional&amp;rsquo;, NULL, &amp;lsquo;Conditional&amp;rsquo; ) always&lt;/p&gt;
&lt;p&gt;FROM dba_log_groups&lt;/p&gt;
&lt;p&gt;ORDER BY owner,table_name,log_group_name;&lt;/p&gt;
&lt;p&gt;选择空闲时段打开所需复制表的附加日志:&lt;/p&gt;
&lt;p&gt;oracle@szgtsp431-or@ecsdb&amp;gt;ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for Oracle&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.4 OGGCORE_19.1.0.0.0_PLATFORMS_191017.1054_FBO&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), Oracle 11g on Oct 17 2019 23:13:12&lt;/p&gt;
&lt;p&gt;Operating system character set identified as US-ASCII.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 1&amp;gt; dblogin userid goldengate,password 123456&lt;/p&gt;
&lt;p&gt;Successfully logged into database.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 2&amp;gt; add trandata ecs.*&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15132  Logging of supplemental redo data enabled for table ECS.DEPT.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15133  TRANDATA for scheduling columns has been added on table ECS.DEPT.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15135  TRANDATA for instantiation CSN has been added on table ECS.DEPT.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15132  Logging of supplemental redo data enabled for table ECS.INFO.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15133  TRANDATA for scheduling columns has been added on table ECS.INFO.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15135  TRANDATA for instantiation CSN has been added on table ECS.INFO.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15132  Logging of supplemental redo data enabled for table ECS.STUDENT_INFO.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15133  TRANDATA for scheduling columns has been added on table ECS.STUDENT_INFO.&lt;/p&gt;
&lt;p&gt;2020-08-14 09:13:54  INFO    OGG-15135  TRANDATA for instantiation CSN has been added on table ECS.STUDENT_INFO.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 3&amp;gt;&lt;/p&gt;
&lt;p&gt;查看日志是否添加成功:&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; select *from (&lt;/p&gt;
&lt;p&gt;  2  select owner,table_name from dba_tables where owner in (&amp;lsquo;BGLWT&amp;rsquo;)&lt;/p&gt;
&lt;p&gt;  3  minus&lt;/p&gt;
&lt;p&gt;  4  select owner,table_name from dba_log_groups)&lt;/p&gt;
&lt;p&gt;  5  order by owner,table_name;&lt;/p&gt;
&lt;p&gt;no rows selected&lt;/p&gt;
&lt;p&gt;返回0行，表示所有的表级附加日志添加成功。&lt;/p&gt;
&lt;p&gt;7.配置管理进程&lt;/p&gt;
&lt;p&gt;oracle@szgtsp431-or@ecsdb&amp;gt;ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for Oracle&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.4 OGGCORE_19.1.0.0.0_PLATFORMS_191017.1054_FBO&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), Oracle 11g on Oct 17 2019 23:13:12&lt;/p&gt;
&lt;p&gt;Operating system character set identified as US-ASCII.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 1&amp;gt; dblogin userid goldengate,password 123456&lt;/p&gt;
&lt;p&gt;Successfully logged into database.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 2&amp;gt; create subdirs&lt;/p&gt;
&lt;p&gt;Creating subdirectories under current directory /home/oracle&lt;/p&gt;
&lt;p&gt;Parameter file                 /oracle/ogg/dirprm: created.&lt;/p&gt;
&lt;p&gt;Report file                    /oracle/ogg/dirrpt: created.&lt;/p&gt;
&lt;p&gt;Checkpoint file                /oracle/ogg/dirchk: created.&lt;/p&gt;
&lt;p&gt;Process status files           /oracle/ogg/dirpcs: created.&lt;/p&gt;
&lt;p&gt;SQL script files               /oracle/ogg/dirsql: created.&lt;/p&gt;
&lt;p&gt;Database definitions files     /oracle/ogg/dirdef: created.&lt;/p&gt;
&lt;p&gt;Extract data files             /oracle/ogg/dirdat: created.&lt;/p&gt;
&lt;p&gt;Temporary files                /oracle/ogg/dirtmp: created.&lt;/p&gt;
&lt;p&gt;Credential store files         /oracle/ogg/dircrd: created.&lt;/p&gt;
&lt;p&gt;Masterkey wallet files         /oracle/ogg/dirwlt: created.&lt;/p&gt;
&lt;p&gt;Dump files                     /oracle/ogg/dirdmp: created.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 3&amp;gt; edit param mgr&lt;/p&gt;
&lt;p&gt;PORT 7809&lt;/p&gt;
&lt;p&gt;DYNAMICPORTLIST 7810-7980&lt;/p&gt;
&lt;p&gt;PURGEOLDEXTRACTS ./dirdat/*, USECHECKPOINTS, MINKEEPDAYS 3&lt;/p&gt;
&lt;p&gt;PURGEDDLHISTORY MINKEEPDAYS 7, MAXKEEPDAYS 10&lt;/p&gt;
&lt;p&gt;LAGREPORTHOURS 1&lt;/p&gt;
&lt;p&gt;LAGINFOMINUTES 30&lt;/p&gt;
&lt;p&gt;LAGCRITICALMINUTES 45&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 6&amp;gt;&lt;/p&gt;
&lt;p&gt;8.配置抽取进程&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 7&amp;gt; add extract extecs, tranlog, threads 1,begin now&lt;/p&gt;
&lt;p&gt;EXTRACT added.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 8&amp;gt; add exttrail ./dirdat/lt, extract extecs&lt;/p&gt;
&lt;p&gt;EXTTRAIL added.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 9&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;EXTRACT     STOPPED     EXTECS      00:00:00      00:00:38    &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 10&amp;gt; edit param  extecs&lt;/p&gt;
&lt;p&gt;EXTRACT extecs&lt;/p&gt;
&lt;p&gt;SETENV (ORACLE_HOME = &amp;ldquo;/oracle/db/11.2.0.4&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;SETENV (ORACLE_SID = &amp;ldquo;ecsdb&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;USERID goldengate, PASSWORD 123456&lt;/p&gt;
&lt;p&gt;EXTTRAIL ./dirdat/lt&lt;/p&gt;
&lt;p&gt;TRANLOGOPTIONS EXCLUDEUSER goldengate&lt;/p&gt;
&lt;p&gt;TRANLOGOPTIONS DBLOGREADER&lt;/p&gt;
&lt;p&gt;DBOPTIONS ALLOWUNUSEDCOLUMN&lt;/p&gt;
&lt;p&gt;FETCHOPTIONS USESNAPSHOT, USELATESTVERSION, MISSINGROW REPORT&lt;/p&gt;
&lt;p&gt;STATOPTIONS REPORTFETCH&lt;/p&gt;
&lt;p&gt;WARNLONGTRANS 1h, CHECKINTERVAL 10m&lt;/p&gt;
&lt;p&gt;DYNAMICRESOLUTION&lt;/p&gt;
&lt;p&gt;DISCARDFILE ./dirrpt/extecs.dsc, APPEND, MEGABYTES 1024&lt;/p&gt;
&lt;p&gt;DISCARDROLLOVER AT 6:00&lt;/p&gt;
&lt;p&gt;REPORTROLLOVER AT 6:00&lt;/p&gt;
&lt;p&gt;REPORTCOUNT EVERY 1 MINUTES, RATE&lt;/p&gt;
&lt;p&gt;DDL INCLUDE MAPPED&lt;/p&gt;
&lt;p&gt;DDLOPTIONS ADDTRANDATA, REPORT&lt;/p&gt;
&lt;p&gt;DDLOPTIONS NOCROSSRENAME, REPORT&lt;/p&gt;
&lt;p&gt;TABLE ECS.*;&lt;/p&gt;
&lt;p&gt;9.配置投递进程&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 11&amp;gt; add extract deliecs, exttrailsource ./dirdat/lt&lt;/p&gt;
&lt;p&gt;EXTRACT added.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 12&amp;gt; add rmttrail ./dirdat/rt, extract deliecs, megabytes 500&lt;/p&gt;
&lt;p&gt;RMTTRAIL added.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 13&amp;gt; edit param deliecs&lt;/p&gt;
&lt;p&gt;EXTRACT deliecs&lt;/p&gt;
&lt;p&gt;PASSTHRU&lt;/p&gt;
&lt;p&gt;DYNAMICRESOLUTION&lt;/p&gt;
&lt;p&gt;RMTHOST 192.168.10.100, MGRPORT 7809&lt;/p&gt;
&lt;p&gt;RMTTRAIL ./dirdat/rt&lt;/p&gt;
&lt;p&gt;DISCARDFILE ./dirrpt/deliecs.dsc, APPEND, MEGABYTES 1024&lt;/p&gt;
&lt;p&gt;DISCARDROLLOVER AT 6:00&lt;/p&gt;
&lt;p&gt;REPORTCOUNT EVERY 1 MINUTES, RATE&lt;/p&gt;
&lt;p&gt;REPORT AT  0:00&lt;/p&gt;
&lt;p&gt;REPORT AT  1:00&lt;/p&gt;
&lt;p&gt;REPORT AT  2:00&lt;/p&gt;
&lt;p&gt;REPORT AT  3:00&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;REPORT AT 22:00&lt;/p&gt;
&lt;p&gt;REPORT AT 23:00&lt;/p&gt;
&lt;p&gt;REPORTROLLOVER AT 00:00&lt;/p&gt;
&lt;p&gt;STATOPTIONS RESETREPORTSTATS&lt;/p&gt;
&lt;p&gt;TABLE ECS.*;     &lt;/p&gt;
&lt;p&gt;10.启动抽取进程&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 20&amp;gt; start extecs&lt;/p&gt;
&lt;p&gt;Sending START request to MANAGER &amp;hellip;&lt;/p&gt;
&lt;p&gt;EXTRACT EXTECS starting&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 21&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;EXTRACT     STOPPED     DELIECS     00:00:00      00:06:06    &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     EXTECS      00:00:00      00:00:01    &lt;/p&gt;
&lt;p&gt;11.配置目标端ogg软件&lt;/p&gt;
&lt;p&gt;一、上传ogg软件并解压&lt;/p&gt;
&lt;p&gt;二、配置ogg软件的环境变量&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ~]$ vi .bash_profile&lt;/p&gt;

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

&lt;h2 class="relative group"&gt;Get the aliases and functions
 &lt;div id="get-the-aliases-and-functions" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#get-the-aliases-and-functions" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;if [ -f ~/.bashrc ]; then&lt;/p&gt;
&lt;p&gt;        . ~/.bashrc&lt;/p&gt;
&lt;p&gt;fi&lt;/p&gt;

&lt;h2 class="relative group"&gt;User specific environment and startup programs
 &lt;div id="user-specific-environment-and-startup-programs" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-specific-environment-and-startup-programs" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PATH=$PATH:$HOME/bin&lt;/p&gt;
&lt;p&gt;export PATH&lt;/p&gt;
&lt;p&gt;export PGHOME=/usr/local/pgsql&lt;/p&gt;
&lt;p&gt;export PGDATA=/data/pgsql&lt;/p&gt;
&lt;p&gt;export OGG_HOME=/data/ogg&lt;/p&gt;
&lt;p&gt;export PATH=$PATH:$PGHOME/bin:$OGG_HOME&lt;/p&gt;
&lt;p&gt;LD_LIBRARY_PATH=$PGHOME/lib&lt;/p&gt;
&lt;p&gt;LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/lib:/usr/lib:/usr/local/lib:$OGG_HOME/lib&lt;/p&gt;
&lt;p&gt;export LD_LIBRARY_PATH&lt;/p&gt;
&lt;p&gt;export ODBCINI=/home/pgsql/odbc.ini&lt;/p&gt;
&lt;p&gt;export DD_ODBC_HOME=/data/ogg&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ~]$ ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for PostgreSQL&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.200714 OGGCORE_19.1.0.0.0OGGBP_PLATFORMS_200628.2141&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), PostgreSQL on Jun 29 2020 03:59:15&lt;/p&gt;
&lt;p&gt;Operating system character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 1&amp;gt;&lt;/p&gt;
&lt;p&gt;12.目标端创建库及表&lt;/p&gt;
&lt;p&gt;ecsdb=# \l&lt;/p&gt;
&lt;p&gt;                                List of databases&lt;/p&gt;
&lt;p&gt;   Name    |  Owner   | Encoding |   Collate   |    Ctype    | Access privileges &lt;/p&gt;
&lt;p&gt;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;+&amp;mdash;&amp;mdash;&amp;mdash;-+&amp;mdash;&amp;mdash;&amp;mdash;-+&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-+&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-+&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-&lt;/p&gt;
&lt;p&gt; ecsdb     | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | &lt;/p&gt;
&lt;p&gt; postgres  | pgsql    | UTF8     | en_US.UTF-8 | en_US.UTF-8 | &lt;/p&gt;
&lt;p&gt; template0 | pgsql    | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/pgsql         +&lt;/p&gt;
&lt;p&gt;           |          |          |             |             | pgsql=CTc/pgsql&lt;/p&gt;
&lt;p&gt; template1 | pgsql    | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/pgsql         +&lt;/p&gt;
&lt;p&gt;           |          |          |             |             | pgsql=CTc/pgsql&lt;/p&gt;
&lt;p&gt;(4 rows)&lt;/p&gt;
&lt;p&gt;ecsdb=# \d&lt;/p&gt;
&lt;p&gt;            List of relations&lt;/p&gt;
&lt;p&gt; Schema |     Name     | Type  |  Owner   &lt;/p&gt;
&lt;p&gt;&amp;mdash;&amp;mdash;&amp;ndash;+&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;+&amp;mdash;&amp;mdash;-+&amp;mdash;&amp;mdash;&amp;mdash;-&lt;/p&gt;
&lt;p&gt; public | student_info | table | postgres&lt;/p&gt;
&lt;p&gt;(1 row)&lt;/p&gt;
&lt;p&gt;ecsdb=# select * from student_info;&lt;/p&gt;
&lt;p&gt; id | name | address &lt;/p&gt;
&lt;p&gt;&amp;mdash;-+&amp;mdash;&amp;mdash;+&amp;mdash;&amp;mdash;&amp;mdash;&lt;/p&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 | 阿大 | 成都&lt;/p&gt;
&lt;p&gt;  7 | 阿二 | 南京&lt;/p&gt;
&lt;p&gt;(7 rows)&lt;/p&gt;
&lt;p&gt;13.配置目标端管理进程并启动mgr&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ogg]$ ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for PostgreSQL&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.200714 OGGCORE_19.1.0.0.0OGGBP_PLATFORMS_200628.2141&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), PostgreSQL on Jun 29 2020 03:59:15&lt;/p&gt;
&lt;p&gt;Operating system character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 1&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     STOPPED                                           &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 2&amp;gt; create subdirs&lt;/p&gt;
&lt;p&gt;Creating subdirectories under current directory /data/ogg&lt;/p&gt;
&lt;p&gt;Parameter file                 /data/ogg/dirprm: created.&lt;/p&gt;
&lt;p&gt;Report file                    /data/ogg/dirrpt: created.&lt;/p&gt;
&lt;p&gt;Checkpoint file                /data/ogg/dirchk: created.&lt;/p&gt;
&lt;p&gt;Process status files           /data/ogg/dirpcs: created.&lt;/p&gt;
&lt;p&gt;SQL script files               /data/ogg/dirsql: created.&lt;/p&gt;
&lt;p&gt;Database definitions files     /data/ogg/dirdef: created.&lt;/p&gt;
&lt;p&gt;Extract data files             /data/ogg/dirdat: created.&lt;/p&gt;
&lt;p&gt;Temporary files                /data/ogg/dirtmp: created.&lt;/p&gt;
&lt;p&gt;Credential store files         /data/ogg/dircrd: created.&lt;/p&gt;
&lt;p&gt;Masterkey wallet files         /data/ogg/dirwlt: created.&lt;/p&gt;
&lt;p&gt;Dump files                     /data/ogg/dirdmp: created.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 3&amp;gt; edit param mgr&lt;/p&gt;
&lt;p&gt;port 7809&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 4&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     STOPPED                                           &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 5&amp;gt; start mgr&lt;/p&gt;
&lt;p&gt;Manager started.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 7&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 8&amp;gt;&lt;/p&gt;
&lt;p&gt;这个时候在源端启动投递进程  deliecs&lt;/p&gt;
&lt;p&gt;oracle@szgtsp431-or@ecsdb&amp;gt;ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for Oracle&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.4 OGGCORE_19.1.0.0.0_PLATFORMS_191017.1054_FBO&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), Oracle 11g on Oct 17 2019 23:13:12&lt;/p&gt;
&lt;p&gt;Operating system character set identified as US-ASCII.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 1&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;EXTRACT     ABENDED     DELIECS     00:00:00      01:06:41    &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     EXTECS      00:00:00      00:00:07    &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 2&amp;gt; start deliecs&lt;/p&gt;
&lt;p&gt;Sending START request to MANAGER &amp;hellip;&lt;/p&gt;
&lt;p&gt;EXTRACT DELIECS starting&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 3&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     DELIECS     00:00:00      01:06:55    &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     EXTECS      00:00:00      00:00:01      &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or) 4&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     DELIECS     00:00:00      00:00:00    &lt;/p&gt;
&lt;p&gt;EXTRACT     RUNNING     EXTECS      00:00:00      00:00:05    &lt;/p&gt;
&lt;p&gt;14.目标端pgsql的参数调整&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or pgsql]$ vi /data/pgsql/postgresql.conf&lt;/p&gt;
&lt;p&gt;wal_level = logical           #minimal, replica, or logical&lt;/p&gt;
&lt;p&gt;max_replication_slots = 10    #max number of replication slots&lt;/p&gt;
&lt;p&gt;max_wal_sender = 10           #maximum number of wal sender processes&lt;/p&gt;
&lt;p&gt;wal_receiver_status_interval=10s  #optional, keep the system default&lt;/p&gt;
&lt;p&gt;wal_sender_timeout  = 60s          #optional, keep the system default&lt;/p&gt;
&lt;p&gt;track_commit_timestamp=off        #optional, keep the system default&lt;/p&gt;
&lt;p&gt;调整参数后重启pgsql&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or pgsql]$ pg_ctl status -D /data/pgsql/ -l /data/pgsql/logfile&lt;/p&gt;
&lt;p&gt;pg_ctl: server is running (PID: 2370)&lt;/p&gt;
&lt;p&gt;/usr/local/pgsql/bin/postgres &amp;ldquo;-D&amp;rdquo; &amp;ldquo;/data/pgsql&amp;rdquo;&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or pgsql]$ pg_ctl stop -D /data/pgsql/ -l /data/pgsql/logfile&lt;/p&gt;
&lt;p&gt;waiting for server to shut down&amp;hellip;. done&lt;/p&gt;
&lt;p&gt;server stopped&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or pgsql]$ pg_ctl start -D /data/pgsql/&lt;/p&gt;
&lt;p&gt;waiting for server to start&amp;hellip;.2020-08-14 11:00:45.360 CST [2817] LOG:  listening on IPv4 address &amp;ldquo;0.0.0.0&amp;rdquo;, port 5432&lt;/p&gt;
&lt;p&gt;2020-08-14 11:00:45.361 CST [2817] LOG:  listening on IPv6 address &amp;ldquo;::&amp;rdquo;, port 5432&lt;/p&gt;
&lt;p&gt;2020-08-14 11:00:45.364 CST [2817] LOG:  listening on Unix socket &amp;ldquo;/tmp/.s.PGSQL.5432&amp;rdquo;&lt;/p&gt;
&lt;p&gt;2020-08-14 11:00:45.375 CST [2818] LOG:  database system was shut down at 2020-08-14 10:50:10 CST&lt;/p&gt;
&lt;p&gt;2020-08-14 11:00:45.378 CST [2817] LOG:  database system is ready to accept connections&lt;/p&gt;
&lt;p&gt; done&lt;/p&gt;
&lt;p&gt;server started&lt;/p&gt;
&lt;p&gt;15.数据源配置&lt;/p&gt;
&lt;p&gt;vi odbc.ini&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ~]$ vi /home/pgsql/odbc.ini&lt;/p&gt;
&lt;p&gt;[ODBC Data Sources]&lt;/p&gt;
&lt;p&gt;PGDSN=DataDirect 10.12 PostgreSQL Wire Protocol&lt;/p&gt;
&lt;p&gt;postgres=DataDirect 10.12 PostgreSQL Wire Protocol&lt;/p&gt;
&lt;p&gt;scott=DataDirect 10.12 PostgreSQL Wire Protocol&lt;/p&gt;
&lt;p&gt;[ODBC]&lt;/p&gt;
&lt;p&gt;IANAAppCodePage=4&lt;/p&gt;
&lt;p&gt;InstallDir=/data/ogg&lt;/p&gt;
&lt;p&gt;[PGDSN]&lt;/p&gt;
&lt;p&gt;Driver=/data/ogg/lib/GGpsql25.so&lt;/p&gt;
&lt;p&gt;Description=DataDirect 10.12 PostgreSQL Wire Protocol&lt;/p&gt;
&lt;p&gt;Database=ecsdb&lt;/p&gt;
&lt;p&gt;HostName=127.0.0.1&lt;/p&gt;
&lt;p&gt;PortNumber=5432&lt;/p&gt;
&lt;p&gt;LogonID=postgres&lt;/p&gt;
&lt;p&gt;Password=123456&lt;/p&gt;
&lt;p&gt;16.连接测试&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ~]$ cd /data/ogg&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ogg]$ ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for PostgreSQL&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.200714 OGGCORE_19.1.0.0.0OGGBP_PLATFORMS_200628.2141&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), PostgreSQL on Jun 29 2020 03:59:15&lt;/p&gt;
&lt;p&gt;Operating system character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 1&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 2&amp;gt; dblogin sourcedb pgdsn userid postgres, password postgres&lt;/p&gt;
&lt;p&gt;2020-08-14 11:35:01  INFO    OGG-03036  Database character set identified as UTF-8. Locale: en_US.UTF-8.&lt;/p&gt;
&lt;p&gt;2020-08-14 11:35:01  INFO    OGG-03037  Session character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Successfully logged into database.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 3&amp;gt;&lt;/p&gt;
&lt;p&gt;17.目标端配置复制进程并启动&lt;/p&gt;
&lt;p&gt;添加checkpoint table&lt;/p&gt;
&lt;p&gt;[pgsql@szgtsp428-or ogg]$ ggsci&lt;/p&gt;
&lt;p&gt;Oracle GoldenGate Command Interpreter for PostgreSQL&lt;/p&gt;
&lt;p&gt;Version 19.1.0.0.200714 OGGCORE_19.1.0.0.0OGGBP_PLATFORMS_200628.2141&lt;/p&gt;
&lt;p&gt;Linux, x64, 64bit (optimized), PostgreSQL on Jun 29 2020 03:59:15&lt;/p&gt;
&lt;p&gt;Operating system character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Copyright (C) 1995, 2019, Oracle and/or its affiliates. All rights reserved.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or) 1&amp;gt; dblogin sourcedb pgdsn userid postgres, password 123456&lt;/p&gt;
&lt;p&gt;2020-08-14 15:22:52  INFO    OGG-03036  Database character set identified as UTF-8. Locale: en_US.UTF-8.&lt;/p&gt;
&lt;p&gt;2020-08-14 15:22:52  INFO    OGG-03037  Session character set identified as UTF-8.&lt;/p&gt;
&lt;p&gt;Successfully logged into database.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 2&amp;gt; add checkpointtable public.chkt&lt;/p&gt;
&lt;p&gt;Successfully created checkpoint table public.chkt.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 4&amp;gt; list table public.*&lt;/p&gt;
&lt;p&gt;public.chkt&lt;/p&gt;
&lt;p&gt;public.chkt_lox&lt;/p&gt;
&lt;p&gt;public.student_info&lt;/p&gt;
&lt;p&gt;public.test&lt;/p&gt;
&lt;p&gt;Found 4 tables matching list criteria.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 34&amp;gt; edit param repl&lt;/p&gt;
&lt;p&gt;REPLICAT repl&lt;/p&gt;
&lt;p&gt;SOURCEDEFS ./dirdef/student_info.def&lt;/p&gt;
&lt;p&gt;SETENV (PGCLIENTENCODING = &amp;ldquo;UTF8&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;SETENV (ODBCINI=&amp;quot;/home/pgsql/odbc.ini&amp;quot;)&lt;/p&gt;
&lt;p&gt;SETENV (NLS_LANG=&amp;ldquo;AMERICAN_AMERICA.AL32UTF8&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;targetdb pgdsn userid postgres, password 123456&lt;/p&gt;
&lt;p&gt;DISCARDFILE ./dirrpt/repl.dsc, purge&lt;/p&gt;
&lt;p&gt;MAP ecs.student_info, TARGET public.student_info;&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 36&amp;gt; add replicat repl,exttrail ./dirdat/rt,checkpointtable public.chkt&lt;/p&gt;
&lt;p&gt;REPLICAT added.&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 38&amp;gt; start repl&lt;/p&gt;
&lt;p&gt;Sending START request to MANAGER &amp;hellip;&lt;/p&gt;
&lt;p&gt;REPLICAT REPL starting&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 55&amp;gt; info all&lt;/p&gt;
&lt;p&gt;Program     Status      Group       Lag at Chkpt  Time Since Chkpt&lt;/p&gt;
&lt;p&gt;MANAGER     RUNNING                                           &lt;/p&gt;
&lt;p&gt;REPLICAT    RUNNING     REPL        00:00:00      00:00:08&lt;/p&gt;
&lt;p&gt;18.测试验证&lt;/p&gt;
&lt;p&gt;首先在目标端创建跟源端student_info一致的表结构&lt;/p&gt;
&lt;p&gt;ecsdb=# create table student_info (id int primary key,name varchar(100),address varchar(100));&lt;/p&gt;
&lt;p&gt;CREATE TABLE&lt;/p&gt;
&lt;p&gt;然后进行数据初始化:&lt;/p&gt;
&lt;p&gt;在源库配置extinit进程&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 17&amp;gt; edit param extinit&lt;/p&gt;
&lt;p&gt;EXTRACT extinit&lt;/p&gt;
&lt;p&gt;userid goldengate, PASSWORD 123456&lt;/p&gt;
&lt;p&gt;REPORTCOUNT EVERY 30 MINUTES, RATE&lt;/p&gt;
&lt;p&gt;DISCARDFILE ./dirrpt/extinit.dsc, APPEND, MEGABYTES 1024&lt;/p&gt;
&lt;p&gt;RMTHOST 192.168.10.100,MGRPORT 7809, compress&lt;/p&gt;
&lt;p&gt;RMTTASK replicat,GROUP replinit&lt;/p&gt;
&lt;p&gt;TABLE ecs.student_info;&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 18&amp;gt; ADD EXTRACT extinit, SOURCEISTABLE&lt;/p&gt;
&lt;p&gt;EXTRACT added.&lt;/p&gt;
&lt;p&gt;在目标端配置replinit进程&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 28&amp;gt; edit param replinit&lt;/p&gt;
&lt;p&gt;REPLICAT replinit&lt;/p&gt;
&lt;p&gt;targetDB pgdsn, USERID postgres, PASSWORD 123456&lt;/p&gt;
&lt;p&gt;discardfile ./dirrpt/replinit.dsc, PURGE&lt;/p&gt;
&lt;p&gt;SOURCEDEFS ./dirdef/student_info.def&lt;/p&gt;
&lt;p&gt;Map ecs.student_info,target public.student_info;&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp428-or as postgres@pgdsn) 29&amp;gt;add replicat repinit, SPECIALRUN&lt;/p&gt;
&lt;p&gt;REPLICAT added.&lt;/p&gt;
&lt;p&gt;开启oracle到pg的数据初始化:&lt;/p&gt;
&lt;p&gt;GGSCI (szgtsp431-or as goldengate@ecsdb) 9&amp;gt; start extinit&lt;/p&gt;
&lt;p&gt;Sending START request to MANAGER &amp;hellip;&lt;/p&gt;
&lt;p&gt;EXTRACT EXTINIT starting&lt;/p&gt;
&lt;p&gt;目标端：(查看初始化行数)&lt;/p&gt;
&lt;p&gt;View report replicat&lt;/p&gt;
&lt;p&gt;查看两边的数据:&lt;/p&gt;
&lt;p&gt;源：&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; set lines 200 pages 200;&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; col name for a10;&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; col address for a10;&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; select * from student_info;&lt;/p&gt;
&lt;p&gt;        ID NAME       ADDRESS&lt;/p&gt;
&lt;hr&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 阿大       成都&lt;/p&gt;
&lt;p&gt;         7 阿二       南京&lt;/p&gt;
&lt;p&gt;         8 阿三       北京&lt;/p&gt;
&lt;p&gt;8 rows selected.&lt;/p&gt;
&lt;p&gt;目标:&lt;/p&gt;
&lt;p&gt;ecsdb=# select * from student_info;&lt;/p&gt;
&lt;p&gt; id | name | address &lt;/p&gt;
&lt;p&gt;&amp;mdash;-+&amp;mdash;&amp;mdash;+&amp;mdash;&amp;mdash;&amp;mdash;&lt;/p&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 | 阿大 | 成都&lt;/p&gt;
&lt;p&gt;  7 | 阿二 | 南京&lt;/p&gt;
&lt;p&gt;  8 | 阿三 | 北京&lt;/p&gt;
&lt;p&gt;(8 rows)&lt;/p&gt;
&lt;p&gt;往源端插入数据:&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; insert into ecs.student_info values (10,&amp;lsquo;aa&amp;rsquo;,&amp;lsquo;bb&amp;rsquo;);&lt;/p&gt;
&lt;p&gt;1 row created.&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; commit;&lt;/p&gt;
&lt;p&gt;Commit complete.&lt;/p&gt;
&lt;p&gt;SQL&amp;gt; select * from student_info;&lt;/p&gt;
&lt;p&gt;        ID NAME       ADDRESS&lt;/p&gt;
&lt;hr&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 阿大       成都&lt;/p&gt;
&lt;p&gt;         7 阿二       南京&lt;/p&gt;
&lt;p&gt;         8 阿三       北京&lt;/p&gt;
&lt;p&gt;        10 aa         bb&lt;/p&gt;
&lt;p&gt;9 rows selected.&lt;/p&gt;
&lt;p&gt;查看目标端:&lt;/p&gt;
&lt;p&gt;ecsdb=# select * from student_info;&lt;/p&gt;
&lt;p&gt; id | name | address &lt;/p&gt;
&lt;p&gt;&amp;mdash;-+&amp;mdash;&amp;mdash;+&amp;mdash;&amp;mdash;&amp;mdash;&lt;/p&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 | 阿大 | 成都&lt;/p&gt;
&lt;p&gt;  7 | 阿二 | 南京&lt;/p&gt;
&lt;p&gt;  8 | 阿三 | 北京&lt;/p&gt;
&lt;p&gt; 10 | aa   | bb&lt;/p&gt;
&lt;p&gt;(9 rows)&lt;/p&gt;
&lt;p&gt;数据已经同步OK了。&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>ogg搭建pg-oracle同步——实操步骤</title><link>https://lastdba.com/2024/08/13/ogg%E6%90%AD%E5%BB%BApg-oracle%E5%90%8C%E6%AD%A5%E5%AE%9E%E6%93%8D%E6%AD%A5%E9%AA%A4/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/ogg%E6%90%AD%E5%BB%BApg-oracle%E5%90%8C%E6%AD%A5%E5%AE%9E%E6%93%8D%E6%AD%A5%E9%AA%A4/</guid><description>&lt;p&gt;ogg软件版本:(19.1.0.0.4)
oracle版本：11.2.0.4
pg版本：pg10
ogg下载地址：&lt;a href="https://www.oracle.com/technetwork/middleware/goldengate/downloads/index.html" target="_blank" rel="noreferrer"&gt;https://www.oracle.com/technetwork/middleware/goldengate/downloads/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;glibc问题处理：&lt;a href="https://www.cnblogs.com/hxlasky/p/16779047.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/hxlasky/p/16779047.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6d5467d7acac.png" alt="img" /&gt;&lt;/p&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%e6%ba%90%e7%ab%af%e5%88%9b%e5%bb%ba%e5%ba%93%e5%8f%8a%e8%a1%a8" 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root&lt;span style="color:#f92672"&gt;@&lt;/span&gt;node2 &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#f92672"&gt;#&lt;/span&gt; su &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;&lt;span style="color:#66d9ef"&gt;Last&lt;/span&gt; login: Tue Jul &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; CST &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; pts&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;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;node2 &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pg_ctl &lt;span style="color:#f92672"&gt;-&lt;/span&gt;D &lt;span style="color:#f92672"&gt;/&lt;/span&gt;opt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pgsql_data &lt;span style="color:#f92672"&gt;-&lt;/span&gt;l logfile &lt;span style="color:#66d9ef"&gt;start&lt;/span&gt;
&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 &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;start&lt;/span&gt;.... done
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server started
&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; test
&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:#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;postgres&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; tab1(id int &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,name varchar(&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;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%e7%9b%ae%e6%a0%87%e7%ab%af%e5%88%9b%e5%bb%ba%e5%ba%93%e5%8f%8a%e8%a1%a8" 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;sqlplus &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sysdba
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SQL&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; ORALZL.tab1(id number &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,name varchar2(&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;h4 class="relative group"&gt;3.解压安装ogg for postgresql
 &lt;div id="3解压安装ogg-for-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="#3%e8%a7%a3%e5%8e%8b%e5%ae%89%e8%a3%85ogg-for-postgresql" 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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--跟ogg for oracle不同，ogg for pg只需要解压。for o需要跑runinstaller
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ id postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid=54323(postgres) gid=54330(postgres) groups=54330(postgres)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ exit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;logout
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# mkdir /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# chown -R postgres /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# chmod -R 755 /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]#
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# ls -l
&lt;/span&gt;&lt;/span&gt;&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 240744
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. 1 root root 87028695 Jul 22 02:51 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# chmod 777 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# unzip 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Archive: 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: ggs_Linux_x64_PostgreSQL_64bit.tar 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: OGG-19.1.0.0-README.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: release-notes-oracle-goldengate_19.1.0.200714.pdf 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# chmod 777 ggs_Linux_x64_PostgreSQL_64bit.tar
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# su - postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ cd /soft
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 soft]$ tar -xf ggs_Linux_x64_PostgreSQL_64bit.tar -C /ogg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;4.pg用户环境变量配置
 &lt;div id="4pg用户环境变量配置" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4pg%e7%94%a8%e6%88%b7%e7%8e%af%e5%a2%83%e5%8f%98%e9%87%8f%e9%85%8d%e7%bd%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg源端&lt;/p&gt;</description><content:encoded>&lt;p&gt;ogg软件版本:(19.1.0.0.4)
oracle版本：11.2.0.4
pg版本：pg10
ogg下载地址：&lt;a href="https://www.oracle.com/technetwork/middleware/goldengate/downloads/index.html" target="_blank" rel="noreferrer"&gt;https://www.oracle.com/technetwork/middleware/goldengate/downloads/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;glibc问题处理：&lt;a href="https://www.cnblogs.com/hxlasky/p/16779047.html" target="_blank" rel="noreferrer"&gt;https://www.cnblogs.com/hxlasky/p/16779047.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6d5467d7acac.png" alt="img" /&gt;&lt;/p&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%e6%ba%90%e7%ab%af%e5%88%9b%e5%bb%ba%e5%ba%93%e5%8f%8a%e8%a1%a8" 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root&lt;span style="color:#f92672"&gt;@&lt;/span&gt;node2 &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#f92672"&gt;#&lt;/span&gt; su &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;&lt;span style="color:#66d9ef"&gt;Last&lt;/span&gt; login: Tue Jul &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; CST &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; pts&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;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;node2 &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pg_ctl &lt;span style="color:#f92672"&gt;-&lt;/span&gt;D &lt;span style="color:#f92672"&gt;/&lt;/span&gt;opt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pgsql_data &lt;span style="color:#f92672"&gt;-&lt;/span&gt;l logfile &lt;span style="color:#66d9ef"&gt;start&lt;/span&gt;
&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 &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;start&lt;/span&gt;.... done
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server started
&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; test
&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:#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;postgres&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; tab1(id int &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,name varchar(&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;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%e7%9b%ae%e6%a0%87%e7%ab%af%e5%88%9b%e5%bb%ba%e5%ba%93%e5%8f%8a%e8%a1%a8" 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;sqlplus &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sysdba
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SQL&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; ORALZL.tab1(id number &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,name varchar2(&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;h4 class="relative group"&gt;3.解压安装ogg for postgresql
 &lt;div id="3解压安装ogg-for-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="#3%e8%a7%a3%e5%8e%8b%e5%ae%89%e8%a3%85ogg-for-postgresql" 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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--跟ogg for oracle不同，ogg for pg只需要解压。for o需要跑runinstaller
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ id postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uid=54323(postgres) gid=54330(postgres) groups=54330(postgres)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ exit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;logout
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# mkdir /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# chown -R postgres /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]# chmod -R 755 /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 ~]#
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# ls -l
&lt;/span&gt;&lt;/span&gt;&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 240744
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. 1 root root 87028695 Jul 22 02:51 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# chmod 777 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# unzip 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Archive: 19100200714_ggs_Linux_x64_PostgreSQL_64bit.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: ggs_Linux_x64_PostgreSQL_64bit.tar 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: OGG-19.1.0.0-README.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inflating: release-notes-oracle-goldengate_19.1.0.200714.pdf 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# chmod 777 ggs_Linux_x64_PostgreSQL_64bit.tar
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[root@node1 soft]# su - postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 ~]$ cd /soft
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@node1 soft]$ tar -xf ggs_Linux_x64_PostgreSQL_64bit.tar -C /ogg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;4.pg用户环境变量配置
 &lt;div id="4pg用户环境变量配置" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4pg%e7%94%a8%e6%88%b7%e7%8e%af%e5%a2%83%e5%8f%98%e9%87%8f%e9%85%8d%e7%bd%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&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;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat .bash_profile
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## .bash_profile&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 the aliases and functions&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; -f ~/.bashrc &lt;span style="color:#f92672"&gt;]&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;. ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## User specific environment and startup programs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PATH:$HOME/.local/bin:$HOME/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GGHOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PG_DATA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/opt/pgsql/pgsql/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PG_DATA:$PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PG_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/opt/pgsql/pgsql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export LD_LIBRARY_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PG_HOME/lib:$LD_LIBRARY_PATH:$GGHOME/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ODBCINI&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/postgres/odbc.ini
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export DD_ODBC_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ source .bash_profile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;5.配置管理进程
 &lt;div id="5配置管理进程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#5%e9%85%8d%e7%bd%ae%e7%ae%a1%e7%90%86%e8%bf%9b%e7%a8%8b" 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:#f92672"&gt;[&lt;/span&gt;postgres@node1 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cd /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ogg&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./ggsci
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Oracle GoldenGate Command Interpreter &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; PostgreSQL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Version 19.1.0.0.200714 OGGCORE_19.1.0.0.0OGGBP_PLATFORMS_200628.2141
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Linux, x64, 64bit &lt;span style="color:#f92672"&gt;(&lt;/span&gt;optimized&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, PostgreSQL on Jun &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 03:59:15
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Operating system character set identified as UTF-8.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;C&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1995, 2019, Oracle and/or its affiliates. All rights reserved.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 2&amp;gt; info all
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Program Status Group Lag at Chkpt Time Since Chkpt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MANAGER STOPPED 
&lt;/span&gt;&lt;/span&gt;&lt;span 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;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 3&amp;gt; create subdirs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating subdirectories under current directory /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Parameter file /ogg/dirprm: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Report file /ogg/dirrpt: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Checkpoint file /ogg/dirchk: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process status files /ogg/dirpcs: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SQL script files /ogg/dirsql: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database definitions files /ogg/dirdef: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Extract data files /ogg/dirdat: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Temporary files /ogg/dirtmp: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Credential store files /ogg/dircrd: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Masterkey wallet files /ogg/dirwlt: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dump files /ogg/dirdmp: created.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 4&amp;gt; edit params mgr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 5&amp;gt; view params mgr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;port &lt;span style="color:#ae81ff"&gt;7809&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 6&amp;gt; start mgr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Manager started.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 7&amp;gt; info all
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Program Status Group Lag at Chkpt Time Since Chkpt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MANAGER RUNNING &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;6.源端postgresql参数调整
 &lt;div id="6源端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="#6%e6%ba%90%e7%ab%afpostgresql%e5%8f%82%e6%95%b0%e8%b0%83%e6%95%b4" 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:#f92672"&gt;[&lt;/span&gt;postgres@node1 ogg&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ vi /opt/pgsql_data/postgresql.conf
&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 style="color:#75715e"&gt;#minimal, replica, or logical&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_replication_slots &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#75715e"&gt;#max number of replication slots&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_wal_sender &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#75715e"&gt;#maximum number of wal sender processes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_receiver_status_interval&lt;span style="color:#f92672"&gt;=&lt;/span&gt;10s &lt;span style="color:#75715e"&gt;#optional, keep the system default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_sender_timeout &lt;span style="color:#75715e"&gt;#optional, keep the system default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;track_commit_timestamp &lt;span style="color:#75715e"&gt;#optional, keep the system default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_receiver_status_interval&lt;span style="color:#f92672"&gt;=&lt;/span&gt;10s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_sender_timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 60s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;track_commit_timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;off&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;调整后重启源端postgresql&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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@node1 ogg&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pg_ctl -D /opt/pgsql_data -l logfile stop
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ogg&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pg_ctl -D /opt/pgsql_data -l logfile start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;7.ogg for pg数据源配置
 &lt;div id="7ogg-for-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="#7ogg-for-pg%e6%95%b0%e6%8d%ae%e6%ba%90%e9%85%8d%e7%bd%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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd /home/postgres/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vi odbc.ini
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;ODBC Data Sources&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PGDSN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DataDirect 7.1 PostgreSQL Wire Protocol
&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;DataDirect 7.1 PostgreSQL Wire Protocol
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scott&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DataDirect 7.1 PostgreSQL Wire Protocol
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;ODBC&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IANAAppCodePage&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;InstallDir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;PGDSN&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Driver&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ogg/lib/GGpsql25.so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;DataDirect 7.1 PostgreSQL Wire Protocol
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database&lt;span style="color:#f92672"&gt;=&lt;/span&gt;test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HostName&lt;span style="color:#f92672"&gt;=&lt;/span&gt;192.168.1.112
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PortNumber&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LogonID&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;Password&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;h4 class="relative group"&gt;8. 连接测试
 &lt;div id="8-连接测试" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#8-%e8%bf%9e%e6%8e%a5%e6%b5%8b%e8%af%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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cd /ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@node1 ogg&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./ggsci
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--dblogin sourcedb pgdsn userid pg, password &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1&amp;gt; dblogin sourcedb pgdsn userid postgres, password postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-07-22 03:10:44 INFO OGG-03036 Database character set identified as UTF-8. Locale: en_US.UTF-8.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-07-22 03:10:44 INFO OGG-03037 Session character set identified as UTF-8.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Successfully logged into database.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 2&amp;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;9.开启表级别附加日志
 &lt;div id="9开启表级别附加日志" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#9%e5%bc%80%e5%90%af%e8%a1%a8%e7%ba%a7%e5%88%ab%e9%99%84%e5%8a%a0%e6%97%a5%e5%bf%97" 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;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 3&amp;gt; dblogin sourcedb pgdsn userid postgres, password postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-07-22 03:21:01 INFO OGG-03036 Database character set identified as UTF-8. Locale: en_US.UTF-8.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-07-22 03:21:01 INFO OGG-03037 Session character set identified as UTF-8.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Successfully logged into database.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 4&amp;gt; add trandata public.tab1 --如果表有主键这步可以忽略
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Logging of supplemental log data is enabled &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; table public.tab1. REPLICA IDENTITY was DEFAULT and is changed to FULL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 5&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 5&amp;gt; info trandata public.tab1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Logging of supplemental log data is enabled &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; table public.t1 with REPLICA IDENTITY set to FULL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;10 在pg上注册抽取进程
 &lt;div id="10-在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="#10-%e5%9c%a8pg%e4%b8%8a%e6%b3%a8%e5%86%8c%e6%8a%bd%e5%8f%96%e8%bf%9b%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;在pg库上注册抽取进程，实际上就是创建了一个复制槽,output plugin 默认使用test_decoding&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 6&amp;gt; Register Extract ext_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2020-07-22 03:25:27 INFO OGG-25355 Successfully created replication slot &lt;span style="color:#e6db74"&gt;&amp;#39;ext_pg_2947c06e0ea2ec74&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; EXTRACT group &lt;span style="color:#e6db74"&gt;&amp;#39;EXT_PG&amp;#39;&lt;/span&gt; in database &lt;span style="color:#e6db74"&gt;&amp;#39;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;h4 class="relative group"&gt;11.配置抽取进程和投递进程
 &lt;div id="11配置抽取进程和投递进程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#11%e9%85%8d%e7%bd%ae%e6%8a%bd%e5%8f%96%e8%bf%9b%e7%a8%8b%e5%92%8c%e6%8a%95%e9%80%92%e8%bf%9b%e7%a8%8b" 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; edit param ext_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;SETENV &lt;span style="color:#f92672"&gt;(&lt;/span&gt; PGCLIENTENCODING &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UTF8&amp;#34;&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; SETENV &lt;span style="color:#f92672"&gt;(&lt;/span&gt;NLS_LANG&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;AMERICAN_AMERICA.AL32UTF8&amp;#34;&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; extract ext_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SETENV &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ODBCINI&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/home/pg/odbc.ini&amp;#34;&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; SOURCEDB pgdsn, USERID pg, PASSWORD &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exttrail ./dirdat/st
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TABLE PUBLIC.TAB1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ----GETTRUNCATES &lt;span style="color:#75715e"&gt;###此特性postgresql 2020-07-22 03:33:37 ERROR OGG-25541 GETTRUNCATES is not valid with OGG EXTRACT on PostgreSQL database version 10.12. PostgreSQL database supports capture of TRUNCATE operations starting from version 11.&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到oracle无法同步truncate命令&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; extract pump_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SETENV &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ODBCINI&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/home/pg/odbc.ini&amp;#34;&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; RMTHOST 172.17.100.150, MGRPORT 7809, compress
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; numfiles &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; RMTTRAIL ./dirdat/rt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TABLE PUBLIC.TAB1;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;12.添加trail和启动抽取和投递
 &lt;div id="12添加trail和启动抽取和投递" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#12%e6%b7%bb%e5%8a%a0trail%e5%92%8c%e5%90%af%e5%8a%a8%e6%8a%bd%e5%8f%96%e5%92%8c%e6%8a%95%e9%80%92" 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;ADD extract ext_pg, TRANLOG,BEGIN now
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; add exttrail ./dirdat/st,extract ext_pg,megabytes &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; add extract pump_pg,exttrailsource ./dirdat/st
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; add rmttrail ./dirdat/rt,extract pump_pg,megabytes &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start ext_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start pump_pg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;13 配置defgen
 &lt;div id="13-配置defgen" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#13-%e9%85%8d%e7%bd%aedefgen" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;如果表结构一直可以配置参数ASSUMETARGETDEFS&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;edit param defgen
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DEFSFILE ./dirdef/tab1.def, PURGE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SOURCEDB pgdsn, USERID pg, PASSWORD &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TABLE PUBLIC.tab1;&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;defgen paramfile /oggpg/dirdef/tab1.prm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;拷贝defgen文件到目标端的dirdef目录下&lt;/p&gt;

&lt;h4 class="relative group"&gt;14.目标端验证trail投递正常
 &lt;div id="14目标端验证trail投递正常" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#14%e7%9b%ae%e6%a0%87%e7%ab%af%e9%aa%8c%e8%af%81trail%e6%8a%95%e9%80%92%e6%ad%a3%e5%b8%b8" 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:#f92672"&gt;[&lt;/span&gt;oracle@lzl dirdat&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cd dirdat
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;oracle@lzl dirdat&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-r----- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; pg pg &lt;span style="color:#ae81ff"&gt;1439&lt;/span&gt; Feb &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 11:02 rt000000000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;15.在pg上注册抽取进程
 &lt;div id="15在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="#15%e5%9c%a8pg%e4%b8%8a%e6%b3%a8%e5%86%8c%e6%8a%bd%e5%8f%96%e8%bf%9b%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&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;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node1 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 6&amp;gt; Register Extract ext_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-07-22 03:25:27 INFO OGG-25355 Successfully created replication slot &lt;span style="color:#e6db74"&gt;&amp;#39;ext_pg_2947c06e0ea2ec74&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; EXTRACT group &lt;span style="color:#e6db74"&gt;&amp;#39;EXT_PG&amp;#39;&lt;/span&gt; in database &lt;span style="color:#e6db74"&gt;&amp;#39;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;h4 class="relative group"&gt;16.配置oracle用户环境变量
 &lt;div id="16配置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="#16%e9%85%8d%e7%bd%aeoracle%e7%94%a8%e6%88%b7%e7%8e%af%e5%a2%83%e5%8f%98%e9%87%8f" 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;export ORACLE_BASE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/oracle/app/oracle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export ORACLE_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$ORACLE_BASE/product/11.2.0/dbhome_1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export ORACLE_SID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;oralzl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export OGG_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/oggfororacle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$ORACLE_HOME/bin:$ORACLE_HOME/OPatch:$PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export TNS_ADMIN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$ORACLE_HOME/network/admin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; export LD_LIBRARY_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$ORACLE_HOME/lib:$OGG_HOME:$ORACLE_HOME/lib32:/lib/usr/lib:/usr/local/lib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;17.配置oracle侧的监听和tns
 &lt;div id="17配置oracle侧的监听和tns" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#17%e9%85%8d%e7%bd%aeoracle%e4%be%a7%e7%9a%84%e7%9b%91%e5%90%ac%e5%92%8ctns" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;ogg for oracle会默认使用TNS_ADMIN下的tns
也可以在配置抽取的时候手动配置
如：&lt;code&gt;USERID goldengate@127.0.0.1:1521/oralzl, PASSWORD 123456&lt;/code&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;18.目标端安装ogg for oracle
 &lt;div id="18目标端安装ogg-for-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="#18%e7%9b%ae%e6%a0%87%e7%ab%af%e5%ae%89%e8%a3%85ogg-for-oracle" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;下载ogg软件
配置oggcore.rsp文件&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;oracle.install.responseFileVersion&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/oracle/oggcore.rsp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INSTALL_OPTION&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ORA11g
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SOFTWARE_LOCATION&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ogg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;START_MANAGER&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;MANAGER_PORT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7809&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DATABASE_LOCATION&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/oracle/db/11.2.0.4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INVENTORY_LOCATION&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/oracle/oraInventory
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UNIX_GROUP_NAME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;oinstall&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;静默安装OGG&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;./runInstaller -silent -nowait -responseFile /home/oracle/oggcore.rsp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;19 oracle库的用户和权限
 &lt;div id="19-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="#19-oracle%e5%ba%93%e7%9a%84%e7%94%a8%e6%88%b7%e5%92%8c%e6%9d%83%e9%99%90" 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;create user goldengate identified by &lt;span style="color:#e6db74"&gt;&amp;#34;123456&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant create session,alter session to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant alter system to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant resource to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant connect to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; any dictionary to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant flashback any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant insert any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant update any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant delete any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; on dba_clusters to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant execute on dbms_flashback to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant create table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant create sequence to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant alter any table to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant dba to goldengate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grant lock any table to goldengate;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;20 目标端mgr进程
 &lt;div id="20-目标端mgr进程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#20-%e7%9b%ae%e6%a0%87%e7%ab%afmgr%e8%bf%9b%e7%a8%8b" 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;edit param mgr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PORT &lt;span style="color:#ae81ff"&gt;7809&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DYNAMICPORTLIST 7810-7980
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PURGEOLDEXTRACTS ./dirdat/*, USECHECKPOINTS, MINKEEPDAYS &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; PURGEDDLHISTORY MINKEEPDAYS 7, MAXKEEPDAYS &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; LAGREPORTHOURS &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; LAGINFOMINUTES &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; LAGCRITICALMINUTES &lt;span style="color:#ae81ff"&gt;45&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;start mgr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;21 目标端配置复制进程
 &lt;div id="21-目标端配置复制进程" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#21-%e7%9b%ae%e6%a0%87%e7%ab%af%e9%85%8d%e7%bd%ae%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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 8&amp;gt; dblogin userid goldengate@127.0.0.1:1521/oralzl,password &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GGSCI &lt;span style="color:#f92672"&gt;(&lt;/span&gt;node2 as postgres@pgdsn&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 9&amp;gt; add checkpointtable goldengate.chkt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Successfully created checkpoint table public.chkt.&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; edit param rep_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPLICAT rep_pg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; USERID goldengate@127.0.0.1:1521/oralzl, PASSWORD &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SOURCEDEFS ./dirdef/tab1.def
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MAP public.tab1, TARGET oralzl.tab1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add replicat rep_pg,exttrail ./dirdat/rt,checkpointtable goldengate.chkt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start rep_pg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 class="relative group"&gt;22 测试同步
 &lt;div id="22-测试同步" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#22-%e6%b5%8b%e8%af%95%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;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;node1 &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;postgres&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:#66d9ef"&gt;c&lt;/span&gt; lzldb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;test&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;d tab1;
&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;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public.tab1&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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&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;20&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;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t1_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&gt;&lt;/span&gt;&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; t2 &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;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:#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; t2;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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; 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;
&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;node2 &lt;span style="color:#f92672"&gt;~&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;sqlplus &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sysdba
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SQL&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; oralzl.tab1; 
&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; id 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;&lt;span style="color:#960050;background-color:#1e0010"&gt;​&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; lzl1 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content:encoded></item><item><title>pg_rewind初识</title><link>https://lastdba.com/2024/08/13/pg_rewind%E5%88%9D%E8%AF%86/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/pg_rewind%E5%88%9D%E8%AF%86/</guid><description>&lt;p&gt;​&lt;/p&gt;

&lt;h2 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="#%e4%bb%80%e4%b9%88%e6%98%afpg_rewind" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg_rewind是pg提供的工具，当2个pg实例时间线（timeline）出现分叉时，pg_rewind可以做实例间的同步。（比如主库运行的情况下，备库failover后运行了一段时间，此时主备的时间线就出现了分叉）
pg_rewind会对比两者的大小，然后把大小不一样的文件从源拷贝到目标，包括配置文件。但是它不会对比没有发生改变的文件，所以pg_rewind在比较大的库，更改少量数据时，运行效率较高。
pg_rewind可以运用在备库failover后，备库即时运行一段时间，也可以把备库拉到和主库一样的状态，重新成为standby。
pg_rewind运行过程中，会对比主（源）备（目标）的差异点，并把主库的差异点后的WAL日志传递给备库。所以，如果主库在差异点之后的WAL也丢失了，那么rewind是不会拷贝不存在的WAL日志的，所以此时备库仍然不会被成功做成standby。解决该问题需要用restore。&lt;/p&gt;</description><content:encoded>&lt;p&gt;​&lt;/p&gt;

&lt;h2 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="#%e4%bb%80%e4%b9%88%e6%98%afpg_rewind" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg_rewind是pg提供的工具，当2个pg实例时间线（timeline）出现分叉时，pg_rewind可以做实例间的同步。（比如主库运行的情况下，备库failover后运行了一段时间，此时主备的时间线就出现了分叉）
pg_rewind会对比两者的大小，然后把大小不一样的文件从源拷贝到目标，包括配置文件。但是它不会对比没有发生改变的文件，所以pg_rewind在比较大的库，更改少量数据时，运行效率较高。
pg_rewind可以运用在备库failover后，备库即时运行一段时间，也可以把备库拉到和主库一样的状态，重新成为standby。
pg_rewind运行过程中，会对比主（源）备（目标）的差异点，并把主库的差异点后的WAL日志传递给备库。所以，如果主库在差异点之后的WAL也丢失了，那么rewind是不会拷贝不存在的WAL日志的，所以此时备库仍然不会被成功做成standby。解决该问题需要用restore。&lt;/p&gt;
&lt;p&gt;！！！在使用pg_rewind时，应备份目标实例。pg_rewind会直接覆盖目标库的文件，如果rewind失败，那么可能目标库无法启动。&lt;/p&gt;

&lt;h2 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%e7%9a%84%e4%bd%bf%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:  entering standby mode
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FATAL:  requested timeline &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; is not a child of this server&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s history
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL:  Latest checkpoint is at 0/6000028 on timeline 1, but in the history of the requested timeline, the server forked off from that timeline at 0/4000098.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:  startup process &lt;span style="color:#f92672"&gt;(&lt;/span&gt;PID 22321&lt;span style="color:#f92672"&gt;)&lt;/span&gt; exited with exit code &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;LOG:  aborting startup due to startup process failure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:  database system is shut down&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时需要用rewind重新拉齐一次主备&lt;/p&gt;
&lt;p&gt;1.配置当前主库的pg_hba
配置pg_rewind的登陆用户登陆源库许可，hba生效需要重启数据库&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 $source/pg_hba.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;host    all       pg         172.17.100.150/32          trust&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_rewind需要使用高权限用户，pg新版本可以授权，pg老版本最好用超级用户。
我当前环境的版本为pg9.6，直接使用OS超级用户&lt;/p&gt;
&lt;p&gt;2.wal_log_hints = on参数配置
将wal_log_hints = on追加到目标库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;vi $dest/postgres.conf
&lt;/span&gt;&lt;/span&gt;&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_log_hints &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;3.pg_rewind命令执行&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 pg96data_sla&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ /pg/pg96/bin/pg_rewind --target-pgdata /pg/pg96data_pri --source-server&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=pg password=oracle  dbname=postgres&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;servers diverged at WAL position 0/4000098 on timeline &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;rewinding from last common checkpoint at 0/4000028 on timeline &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;Done!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;4.配置备库参数
更改postgres.conf和recovery.conf中的IP、端口、目录等配置，pg_rewind会把配置文件也cp过来&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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 pg96data_pri&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ mv recovery.done recovery.conf
&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 pg96data_pri&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ vi recovery.conf
&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 pg96data_pri&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ vi postgres.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;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-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 pg96data_pri&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ /pg/pg96/bin/pg_ctl -D /pg/pg96data_sla -l /pg/pg96data_sla/server.log start 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server starting
&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 pg96data_sla&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ psql -p5433 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql &lt;span style="color:#f92672"&gt;(&lt;/span&gt;9.6.17&lt;span style="color:#f92672"&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:#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;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%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 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%e5%91%bd%e4%bb%a4%e6%8a%a5%e9%94%99%e4%b8%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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;could not fetch remote file &lt;span style="color:#e6db74"&gt;&amp;#34;global/pg_control&amp;#34;&lt;/span&gt;: ERROR:  must be superuser to read files
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Failure, exiting&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;postgres&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;# \du&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;                                    List of roles
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  Role name  |                         Attributes                         | Member of 
&lt;/span&gt;&lt;/span&gt;&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         | Replication                                                | &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg          | Superuser, Create role, Create DB, Replication, Bypass RLS | &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rewind_user |                                                            | &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;pg用户是pg server自带的超级用户，跟pg安装用户相同。os的安装用户肯定有修改pg_control的权限&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_rewind --target-pgdata /pg/pg96data_pri --source-server&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=pg password=oracle  dbname=postgres&amp;#39;&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_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%e5%91%bd%e4%bb%a4%e6%8a%a5%e9%94%99%e4%ba%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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;could not connect to server: FATAL:  no pg_hba.conf entry &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; host &lt;span style="color:#e6db74"&gt;&amp;#34;172.17.100.150&amp;#34;&lt;/span&gt;, user &lt;span style="color:#e6db74"&gt;&amp;#34;rewind_user&amp;#34;&lt;/span&gt;, database &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;Failure, exiting&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;没有配置pg_hba.conf连接
解决办法：配置用户的pg_hba，例如&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;host    all       pg         172.17.100.150/32          trust&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_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%e5%91%bd%e4%bb%a4%e6%8a%a5%e9%94%99%e4%b8%89" 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-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 pg96data_sla&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$   /pg/pg96/bin/pg_rewind --target-pgdata /pg/pg96data_pri --source-server&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=pg password=oracle  dbname=postgres&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;target server needs to use either data checksums or &lt;span style="color:#e6db74"&gt;&amp;#34;wal_log_hints = on&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;/p&gt;
&lt;ol&gt;
&lt;li&gt;full_page_writes （默认开启）&lt;/li&gt;
&lt;li&gt;wal_log_hints 设置成 on 或者 PG 在初始化时开启 checksums 功能 
解决办法：将wal_log_hints = on配置到目标库postgres.conf，启动再关闭一次目标库（目标库本来就是关闭的，必须启动再关闭一次，不然参数不会生效）&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-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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wal_log_hints &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;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pg@lzl pg96data_sla&lt;span style="color:#f92672"&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;span style="display:flex;"&gt;&lt;span&gt;server starting
&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 pg96data_sla&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$  /pg/pg96/bin/pg_ctl -D /pg/pg96data_pri -l /pg/pg96data_pri/server.log stop
&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;/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%82%e8%80%83%e6%96%87%e6%a1%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/9.6/app-pgrewind.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/9.6/app-pgrewind.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;​&lt;/p&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>读书笔记——《educated 》和《atomic habits》</title><link>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0educated-%E5%92%8Catomic-habits/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0educated-%E5%92%8Catomic-habits/</guid><description>&lt;p&gt;​其实很早之前就想写写这两本书的读后感了。我很喜欢看书，但是极其讨厌写作，坚持写博客对于我来说简直就是神迹。我喜欢看书因为我喜欢和相信教育的力量。对于我有多讨厌写作，我想讲个我的小故事。&lt;/p&gt;</description><content:encoded>&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="#%e6%88%91%e4%b8%8d%e5%96%9c%e6%ac%a2%e5%86%99%e4%bd%9c%e6%96%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        我不喜欢写作可以说是天生的。从小学开始，我就不写日记、作文。每次寒暑假作业都要每天一篇日记，我一篇也不会写。我还记得开学的时候要交暑假作业，老师威胁我说你补不齐就上不了学，可是我最后还是没有写一个字，坐在教室照常上课。后来我们班主任老师不知道是什么任务，要交几个典型缺点的孩子改正缺点的方法，全班只有4、5个人被选中，有个是体育不好的、有个是脾气不好的，而我是那个作文不好的！关键是要写一篇改正缺点的作文！我不会写作文为什么要我写改掉不会写作文的作文啊？？？拖了2周，其他同学都交了，我硬是一个字没憋出来。班主任亲自指导我，她说你平时走在路上看到任何东西都可以写成句子，比如看到蓝天，你内心可以造一个“这个天空是万里无云的”这种句子，时常锻炼造句能力可以运用到写作中，你也可以想想还有没有其他办法可以改掉不爱写作的坏毛病。又过了一周，我把她给我说的话原封不动的写了进去，我能看到她眼里的无奈。后来，到了初中，我机智的跟语文科代表搞好了关系，让她收作业的时候，不要把我的名字写到未交作业名单上去，于是我躲过了3年初中。再后来，到了高中，有次以自己的方式尬写了一篇作文，拿了30分给我心理造成了沉重打击，于是每次月考考语文的时候，我都不会写作文，我想反正是模拟又不是高考，60分哥们不要了。最后我在高考和前2次模拟的时候，像八股文一样把屈原李白硬往作文模板里套，我发现没有套不进去的，于是混过了高考作文这个坎。大学就不用说了，我的手已经不会拿笔了。
        是的，就是这种奇特的写作心理，我讨厌作文。但是工作后我逐渐明白，好记性不如烂笔头的道理，看再多书也得自己沉淀。理想、家庭、工作的压力使我必须要改变自己，我需不需要这个技能似乎不重要，社会需要这个技能我就应该尝试改变。写东西不仅可以鞭策自己，也是一种记录成长、记录人生的方式。甚至我自己写的技术文章，我几年后还得回来仔细看，仔细复习。&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%af%bb%e7%82%b9%e5%8e%9f%e8%91%97%e6%9c%89%e5%88%a9%e4%ba%8e%e8%ba%ab%e5%bf%83%e5%81%a5%e5%ba%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        《educated》和《atomic habits》我都是看的英语原版的，自己本身还是有一丢丢英语的底子，加上那段时间考研，我想提升一下自己的英语阅读能力，所以选择了英语原版著作。刚开始读英语原著，还是很困难的，很多单词都不认识，不认识的就查翻译标注在书上，读的十分缓慢。但随着阅读的深入，标注的单词越来越少。并不是我很快的记住了很多不会的单词，而是一本书，有些重要单词是反复出现的，而有些出现次数很少也不会影响阅读，还有刚开始你并不知道书要讲什么，理解书的内容延迟比较高，后面你知道这本书将要讲什么时候，阅读自然会快很多。比如ridge这个单词，刚开始出现频率非常高，后来就记住这个单词了，有些类似的单词我也记不住了，但是我知道他们是某个地理名词，山顶、谷底、田垦什么的，即时没记住也不影响我继续阅读。英语原著都是这样，刚开始看起来比较困难，越往后读越快。&lt;/p&gt;

&lt;h2 class="relative group"&gt;educated
 &lt;div id="educated" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#educated" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;      《educated》的中文书名《你当像鸟飞往你的山》，我十分想吐槽这个标题，educated是全书的精神内涵，在书的最后还终极点题call it educated，十分的精彩。这个中文标题像shit一样，毫无本书的精髓。作者的亲身经历就是一个传奇，从美国的某个角落山咔咔里走出来的孩子，靠着自己的努力读书读到剑桥。他父亲是一个没有文化、反社会、没有基本物理认知的人，自身的无知也导致家人受伤甚至残疾，而且不赞同孩子去读书，甚至认为读书是政府的洗脑方式，有太多奇葩行为。他哥哥也有人格问题，把她的头按在肮脏的马桶上让她求饶，第二天跟任何事都没发生一样继续当她的好哥哥&amp;hellip;后来作者读书靠找到出路，最后也不想回到那个山谷。看到最后我总是想起我自己的经历，当然我没有那么极端的环境，也没有那么传奇的经历，可是我好像可以理解educated后，理解家人的行为总觉得不太自然。不是说上个大学飘了，而是这个代沟是真实存在的。我非常认同education的重要性，如果不是我家人砸锅卖铁全力支持我读书，我们的家的条件根本不会改变。如果你真的沉溺于贫穷，你才会知道摆脱贫穷的欲望有多么强烈，而教育是我们这类人几乎唯一的出路。《educated》是一本好书，文笔清晰、舒适的语句结构、适合现代人的阅读节奏、精彩的故事、深刻的主旨，作为人生第一本英语原著非常合适。&lt;/p&gt;

&lt;h2 class="relative group"&gt;atomic habits     
 &lt;div id="atomic-habits" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#atomic-habits" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        《atomic habits》中文名《原子习惯》，我也忘记了是怎么找到这本书的，它改变了对行为的认知。养成良好的习惯其实并不困难，只是绝大多数人不知道怎样去养成良好的习惯。很多人都曾经说过，我要在几个月内看几本书、跑多少步减多少肥，但是他们很难完成。养成好习惯需要你真的喜欢这个习惯、改变自己的思维、减少做这个动作的复杂度、把不利因素放远一点、形成奖励机制等等。你想成为某种人时，不应该想着如何成为这种人，而是要思考这种人正在做什么，你应该学着做。比如说戒烟，如果的大脑认为你现在处于戒烟状态，是很难戒烟的，如果一个人给你一根烟，你说你在戒烟，他可能几句话就能让你把烟抽起来。但是如果你本身就认为你不抽烟，注意是你内心的真实想法，别人给你烟的时候，你会说你不抽烟，这烟可能就不用抽了。还有一些小细节，比如养成晚上读书的习惯，你需要戒掉刷手机的习惯。你需要把书从书柜放置在床头，这样更方便你拿取，把手机放在床尾，让起床成为拿手机的屏障，这样更有利于你随手拿书而不是手机。如果拿起书还是有困难，转换一下思想，“看书”这个行为可能困难，但是把这个动作拆解，“把书拿在手上”或者翻看第一页“成为你的思想目标，看书的启动动作很简单，也比较容易完成，看完第一页后再考虑之后的事，实际上你看了第一页很难不看第二页。当然还有很多非常好的关于养成好习惯和扔掉坏习惯的建议，字字珠玑引人入胜。看完《atomic habits》后，如果我想要某种习惯，我会先考虑书中的指导然后再计划如果实施，而不是心血来潮。&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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        At last，这2本书对我自身的影响非常大，一部传奇自传、一部颠覆行为的书，它们都不是那种看完一段时间后就会忘光光的著作。对于培养读书这个习惯的起步书籍非常合适，特别是想看英语原著的小伙伴，真不推荐《傲慢与偏见》、《百年孤独》这些著作，虽然他们经典，但是对于读者的影响程度非常低，而且著作时间太久远，有些英语单词和语法太古老了，不太适合刚接触英语著作的人。如果从《atomic habits》这本书来看这个观点，看这些英语经典著作不仅难度较高、而且没有利己收益，很难养成习惯。&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《Sapiens : A Brief History of Humankind》</title><link>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0sapiens-a-brief-history-of-humankind/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0sapiens-a-brief-history-of-humankind/</guid><description>&lt;p&gt; 这是一本我读了很久的书。书很厚，书所涉猎的内容也很广，原著啃起来还是有些困难，不过值得庆幸的是最终还是读完了，就在今天(2023年2月），成就感拉满。&lt;/p&gt;
&lt;p&gt;        《Sapiens : A Brief History of Humankind》中文译名《人类简史：从动物到上帝》。为什么总是感觉中文译名怪怪的，找不到重点。这本书的重点是人类历史本身，是一篇全面介绍人类文明发展的宏伟史书。我本身比较喜欢了解一些人类历史方面的东西，沉浸于这种历史的承重感和人类文明发展的生命力。&lt;/p&gt;</description><content:encoded>&lt;p&gt; 这是一本我读了很久的书。书很厚，书所涉猎的内容也很广，原著啃起来还是有些困难，不过值得庆幸的是最终还是读完了，就在今天(2023年2月），成就感拉满。&lt;/p&gt;
&lt;p&gt;        《Sapiens : A Brief History of Humankind》中文译名《人类简史：从动物到上帝》。为什么总是感觉中文译名怪怪的，找不到重点。这本书的重点是人类历史本身，是一篇全面介绍人类文明发展的宏伟史书。我本身比较喜欢了解一些人类历史方面的东西，沉浸于这种历史的承重感和人类文明发展的生命力。&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%ae%a4%e7%9f%a5%e9%9d%a9%e5%91%bd%e4%b8%8e%e8%99%9a%e6%9e%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        一般人类史观点认为，人类第一次重要进化或者revolution是学会使用工具。就像《太空漫游》里那样，几只猩猩拿着骨头敲打，经典bgm响起~~不过这是科幻。《人类简史》认为人类的第一次重要revolution，是cognitive revolution认知革命，认知革命是区分人和动物的重要标志。人类学会直立行走不仅解放了双手，其实更重要的是解放了思想。四肢奔跑的动物，之所以没有进化，是因为残酷的自然环境让它们必须拥有更强壮的身体和四肢才能跑的快，而直立行走显然是跑不快的，群居和使用工具使我们不需要太快的奔跑。但是群居和工具不是智人独有的属性，许多动物都是群居，猩猩也会使用工具。但是智人学会了制造武器、船、更多人数的群居生活，他们从非洲走到中东，到欧洲和比他们强壮的多的尼安德特人交战并最终占领领地，走向远东，跨越白令海峡到达美洲，甚至坐船到澳大利亚。而这种制造更复杂的工具和交流的能力，就是认知革命带来的。&lt;/p&gt;
&lt;p&gt;        尼安德特人本身已经灭绝，但是最新的研究发现，绝大部分人类拥有少量的尼安德特人基因，除了非洲土著没有。这说明尼安德特人并没有被智人灭绝，少数尼安德特人与智人融合了，并走向了世界。这也是佐证人类非洲起源的重要证明。&lt;/p&gt;
&lt;p&gt;        书中对认知革命讲了一个经典的例子：假设河边有一只狮子，一个智人看到了那只狮子并把这件事告诉了其他人，那么其他人会在大脑中构造”河边有狮子“这样一个事情，即便大家不知道那里到底有没有狮子。这个事情的前提是智人必须学会构思，更重要的是学会了这项技能后，便有了后来的语言交流、虚构、谎言、权利、社会结构···尼安德特人显然比智人交流的信息要少的多。&lt;/p&gt;
&lt;p&gt;        认知革命对文明的发展影响非常大，它可以构造更多并不存在的东西，比如神、宗教、权利、金钱、社会结构、王朝···。比如公司，公司实际上是也是一种社会结构，它其实并不存在，公司也可以是文件袋里带着章的4A纸，但那只是一张白纸而已。员工认为公司存在是因为他们大脑相信公司存在，所有人都相信公司存在，但是公司实际上只是人脑中的一种虚构，这个真实的世界是不存在公司这个实体的。&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%b4%a7%e5%b8%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        金钱是怎么来的？在没有金钱的时代，一个稳定的社会结构出现以物换物的交易，但是当交易种类增多后，以物换物的等价交换等式数会程指数上涨。当鞋子和钉耙进行交易时，这是很简单的一物换一物，再增加一个物品 驴，我们也可以有3中交换等式 鞋-耙、耙-驴、鞋-驴，如果货物再增多，这个交换等式数就是不排列组合数，这还不考虑多物换一物的情况。这时一个中介物——金钱出现了，它将这个问题迎刃而解，所有东西只需要与金钱划等式即可。金钱充当了所有物品的等价交换物，我们的交易便利性得到极大缓解。最初的金钱种类非常多，常见的是贝壳，如果贝壳过于方便获取，那么有人就可以买下市场上的所有东西，所以以贝壳为金钱的文明一般都在内陆。由于金钱大家都揣兜里买东西或者藏家里囤着，并担心过于廉价的方式获得货币会冲击市场，所以金子这种稀有、不宜变质、难以开采的矿石资源成为了人类长时期的重要货币。在古代欧洲，很多国家的国王都会发行印有自己头像或logo的金币，以至于欧洲的金币种类超级多。而古代中国还是有些不一样，刚开始像三星堆文明发掘出的贝壳、再到春秋战国的青铜货币、再到朝代更迭期金银铜、交子。我们没有像欧洲那样一直使用金子，主要还是人口太多而金存量太少，导致金子价值过高，需要一些其他金属来制造货币梯度缓和交易量级差距。&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="#%e5%93%a5%e4%bc%a6%e5%b8%83%e5%92%8c%e9%83%91%e5%92%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        大航海时代，工业革命早期。欧洲人热衷于探索世界未知领域。在欧洲人知道地球是圆的以后，由于没有很好的测绘条件，哥伦布从欧洲出发往西走，准备到印度india。他们穿越大西洋来到了一片土地，并见到了当地人，他们以为到了印度，把那些人叫indian，中文翻译印第安人。直至今日漂亮国的indian还是两个含义：印度人或印第安人。欧洲人知道了这个世界还有很多角落我们未曾驻足（至少是较现代的文明未曾驻足），他们重绘了世界地图，把未知的领域用海怪和巨兽来代替。这种地图现在仍被广泛运用于游戏地图，比如说游戏《文明6》的地图，未探索领域用海怪地图展示，等待发现与探索。欧洲人热衷于发现新的土地，随后南美、新西兰、澳大利亚、海洋上的许多小岛被发现和插旗。如果本地文明过于落后，比如阿兹特克文明、印第安文明、毛衣文明、达斯玛尼亚文明等等都遭到残忍屠杀，土地皆被白人占领。&lt;/p&gt;
&lt;p&gt;        当阿兹特克文明遭遇到穿着泛光的铁铠甲和锋利铁剑的西班牙人，他们以为那些人是神，他们无法理解坚硬的衣服和武器，那一定是神派来的，而后却被”高等文明“欺骗和屠杀。&lt;/p&gt;
&lt;p&gt;        郑和的舰船被称为dragon boat（原文是这样写的，甚至还配了图，我觉得可能是搞错了或者西方人认为带有龙头的船都是dragon boat），要比哥伦布发现新大陆的船大几倍，比哥伦布还早1、2百年，郑和舰队用更先进的科技发现了新的土地，但是并没有去占领，而是与当地人贸易。书中的观点认为，欧洲人更具冒险性和侵略性，从而开启大航海时代。感觉欧洲人对明朝有较友好的态度，《文明6》中，只有3个天朝文明领袖：秦始皇、武则天、朱棣。只有明朝的朱棣是发展种田流的。&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%e5%b0%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        重新回溯人类文明的发展，可以了解我们是怎么来的，还可以知道我们现在在做什么，探索我们会往哪里去。也因为喜欢这类题材而很喜欢《文明6》《人类》这样的策略游戏，但你种植水稻、圈养马、挖出盐、铁矿、煤、石油、铀···时，会有一种人类进化的快感。&lt;/p&gt;
&lt;p&gt;        我想用我玩了400多个小时的游戏《文明6》来结束此篇：”从水下第一个生命的萌芽开始……到石器时代的巨型野兽……再到人类第一次直立行走，你已经历许多。现在，开启你最伟大的探索吧“。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《富爸爸穷爸爸》</title><link>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%AF%8C%E7%88%B8%E7%88%B8%E7%A9%B7%E7%88%B8%E7%88%B8/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%AF%8C%E7%88%B8%E7%88%B8%E7%A9%B7%E7%88%B8%E7%88%B8/</guid><description>&lt;p&gt;《富爸爸穷爸爸》，以前不屑读这种书。这种书就是那种走进书店放在门口展销位的成功学著作，一眼看上去没什么实在的内容，看上去很不靠谱，感觉就是骗一些社会底层又做着暴富梦的人来买的，但是由于自身原因或环境局限根本无法将书中建议带入自身。再者说了，聪明人是不会读这种没涵养的书的~书名还low的一笔！
有一段时间喜欢看B站的《老高与小茉》，有一集在讲这本书，说的神神忽忽的，而且是世界畅销书，所以买来看看到底有多么神奇。&lt;/p&gt;</description><content:encoded>&lt;p&gt;《富爸爸穷爸爸》，以前不屑读这种书。这种书就是那种走进书店放在门口展销位的成功学著作，一眼看上去没什么实在的内容，看上去很不靠谱，感觉就是骗一些社会底层又做着暴富梦的人来买的，但是由于自身原因或环境局限根本无法将书中建议带入自身。再者说了，聪明人是不会读这种没涵养的书的~书名还low的一笔！
有一段时间喜欢看B站的《老高与小茉》，有一集在讲这本书，说的神神忽忽的，而且是世界畅销书，所以买来看看到底有多么神奇。&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%bc%80%e5%a7%8b%e8%af%bb%e7%94%b5%e5%ad%90%e4%b9%a6%e4%ba%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;个人是纸质书的忠实拥趸，喜欢那种看完一整本书，然后放在书架收藏的感觉——”这一书架都是我的知识“的feeling。本身是不太喜欢电子书的，一种看完就完了的感觉，重拾电子书有3个原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最近把常用的打发时间app都干掉了，需要一个不那么洗脑的app，拿出手机时能首先点开的app&lt;/li&gt;
&lt;li&gt;电子书还是比纸质书方便，随时都能拿出来看&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;利用地铁的碎片时间。之前考研的时候给自己规划了细致的时间计划表，其中就包括地铁时间。因为已经养成了地铁学习的习惯，还是不想放弃。推荐一下我的考研总结精华：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/125101488?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;我是如何考上武汉大学在职研究生的&lt;/a&gt;_
把我之前的实际计划稍微调整了一下，现在不用这么投入的去背单词了，所以可以替换成看电子书。我把地铁时间分成了2块：上班地铁时间和下班地铁时间



&lt;img src="https://lastdba.com/img/csdn/f3d9749383d1.png" alt="abc" /&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%a9%b7%e7%88%b8%e7%88%b8%e5%92%8c%e5%af%8c%e7%88%b8%e7%88%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;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%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;书中说，我们的教育体系都是在培养人们的工作能力，而不是培养挣钱能力。这句话非常赞同，但是我仍然相信教育的力量。作者也不是不让人们去读书接收教育，教育对于挣钱也非常重要，我们需要了解这个世界的基本运作原理和规则，这样也能帮助寻找适合自身的挣钱的办法。 &lt;br&gt;
从作者当时的家庭条件来看，可能对于富爸爸来说是比较贫穷，但是对于真正的穷人来说，已经完全不是穷人的家庭条件了。我感觉我的条件还没有达到全身心的投入投资和挣钱的道路中。如果有一天有点闲钱并且自身的管理、社交、决策能力达到一定水平，我也许会去寻找挣钱的办法。现在还想不了那么多，把代码敲好了，先把坑填上再说。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a5205d91518d.png" alt="ass" /&gt;
文中这个学习金字塔令人印象深刻，被动学习能记住的东西真的非常非常少。所以我坚持频繁的写文章，包括读书笔记这类的。几年的半夜维护数据库，遇到问题，现在还影响深刻，实战确实是记忆最深的。不过话说回来，实战是可遇不可求的，阅读和自我学习是成本最低也最容易养成习惯，也是提升能力性价比最高的方式，它也没那么“被动”。学习金字塔的“被动”指的是知识被主体接收，“主动”指主体输出知识。这也增强了我记录和分享的动力，无论是技术的还是非技术的。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《马斯克》</title><link>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E9%A9%AC%E6%96%AF%E5%85%8B/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E9%A9%AC%E6%96%AF%E5%85%8B/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9e00679bd411.png" alt="abc" /&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%a4%a9%e8%b5%8b%e5%bc%82%e7%a6%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        马斯克的祖辈因为热爱冒险，从美国移民到南非生活，他的外祖父甚至驾驶飞机从非洲飞到澳大利亚。马斯克出生于南非，从小马斯克就表现出惊人的记忆力，而且非常聪明。她母亲梅耶马斯克跟老师说：“我儿子是个天才”，老师说“是的，每个母亲都是这样说的”，梅耶：“不，我是说他真的是个天才”。小时候马斯克表现得有点“反应迟钝”，他妈妈说，别人在跟他说话时他毫无反应，她以为马斯克脑子有问题甚至去看了医生。但是后面她发现，马斯克只是沉浸在自己的世界里思考。马斯克小时候甚至可以把图书馆的书全部看完，再让图书馆再去搞更多的书···&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9e00679bd411.png" alt="abc" /&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%a4%a9%e8%b5%8b%e5%bc%82%e7%a6%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e5%88%b0%e8%be%be%e7%be%8e%e5%9b%bd" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        由于南非的环境不如人意 ，即将读大学的马斯克选择了二级跳。他先到加拿大读大学，再到美国读硕士。最终到达美国的马斯克沉浸于硅谷的工作环境，科技行业太需要他这种聪明又拼命的年轻人了。而硅谷的科技氛围和自由施展特长的文化另马斯克沉浸其中。​​​​​​​&lt;/p&gt;

&lt;h2 class="relative group"&gt;zip2和paypal
 &lt;div id="zip2和paypal" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#zip2%e5%92%8cpaypal" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        不久马斯克创办了ZIP2，相当于公司版的在线地图，虽然我们现在对于在线地图非常熟悉，但那个时候美国的互联网行业才起步不久，这些都是新鲜玩意儿。后来经过很多曲折，zip2确实也成长了起来。个人觉得zip2的模式再往后发展，不往在线地图或大众点评这种方向做很难活下来，最后有冤大头用3亿美金把zip2买下来，直接让马斯克成为千万富翁，成为硅谷科技富豪。其实能看出来，zip2当时内部分化严重，公司经营方向也有问题，马斯克也没有绝对的话语权，估计早就想甩锅了。&lt;/p&gt;
&lt;p&gt;        在离开zip2前马斯克已经在盘算和招兵买马搞在线支付。当时这个世界还没有支付宝这种东西··· 。马斯克认为传统金融行业过于保守，有非常大的机会改变这个行业模式。但是很多银行家并不认为互联网金融能做起来，因为互联网金融无法处理网络安全问题，毕竟金融问题如果出一点差错影响会极大。刚开始马斯克成立的公司不是paypal，而是X.com，后来与paypal合并并保留了前者的名字。刚开始X.com遭到了非常多的攻击，而X.com活了下来，他们当时的安全防护机制对于后来在线支付领域影响很大。而paypal后来被ebay收购，马斯克收入上亿美元，又挣了一大笔。&lt;/p&gt;

&lt;h2 class="relative group"&gt;spaceX和特斯拉
 &lt;div id="spacex和特斯拉" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#spacex%e5%92%8c%e7%89%b9%e6%96%af%e6%8b%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        zip2和paypal对于马斯克来说，是对自己行业敏感度和商业能力的认可，同时也有人质疑马斯克的执行和决策能力，也就是当CEO的能力。一如既往的，马斯克认为这些行业过于保守和老旧。马斯克很喜欢招募那些能力极强的高校毕业生，也不愿意招募那些经验老道思想保守的行业精英。他几乎同时运营了两家公司，而这两家公司长时间都完全没有产品产出，关键是，想想也知道，造火箭这事儿是得有多烧钱。经过几次火箭发送失败后，马斯克发动了自己的特别技能：fire··而正值金融危机没有人愿意投钱，他也将自己的全部家当投入到两家公司。spaceX经过几次失败在FALCON火箭终于完成第一个私人公司成功发射卫星的壮举后，获得了NASA的10亿美元订单。特斯拉也在厚脸皮的向之前下单购买roadster的客户再要点钱后，因为开发一辆如此新概念的新能源车成本远超预期，终于制造出了成品车，并打造了公路新能源充电体系和电车工厂。在同时成功经营两家颠覆行业的公司后，没有人再质疑马斯克的能力。&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%ba%e4%ba%86%e4%ba%ba%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        马斯克的成功离不开他优秀的品质，对未来科技的敏感性、快速理解新行业的知识、识别人才的能力、自由开放的科技和市场环境、长时间工作和执行力···，但是他不被人喜欢的点包括对员工非常冷库，对于一些忠心耿耿的人说fire就fire。作为一个打工仔的我深深理解自我付出但是被公司认可的感受。我在读这本书时，甚至可以感受到美国资本家是真剥削工人。一次一个员工因为不想错过女儿的出生而错过了公司的聚会，马斯克写邮件喷他，你想沉浸于家庭的里短还是马不停蹄的改变世界？毒师可不想错过女儿的出生。&lt;/p&gt;
&lt;p&gt;        几年前我读《乔布斯》传的时候，想着怎么会有这么偏执的人，但是就是这种人改变了移动行业，带来了智能手机革命，乔布斯也太强了。看完《马斯克》后，现在感觉马斯克比乔布斯还强。特斯拉、spaceX、太阳城都是在向着人类的未来发展，未来世界似乎启动了步伐，能看到它慢慢来到我们的世界。&lt;/p&gt;
&lt;p&gt;        马斯克的火星计划似乎终于见到了一些曙光，几十年来美国航天业几乎停滞不前，他带来了新的模式，并再次把航天业带入热门领域。但是这一切也有不确定因素。如果载人发生发生爆炸造成人员上网，SpaceX可能又会落入深渊。再者特斯拉在未来发现有严重缺陷需要召回，股价也会暴跌。&lt;/p&gt;
&lt;p&gt;        如果你可以成为登陆火星的第一个人类，你会去做吗？马斯克想过，并且他真有可能成为那样的人。但是马斯克不会那样做，书中的原话：我想去，但我不必去，重点是让很多人能够去火星。就好像波音公司老板当飞机试飞员，对于太空开发是不明智的。就算永远不去太空也没什么，重点是尽可能延长人类的寿命。&lt;/p&gt;
&lt;p&gt;        未了人类而工作，这个主题确实令人心潮澎湃。我玩几天几夜的《文明6》，从拿棒子的原始人到点燃火箭，就是为了发射那一刻，人类成为跨行星物种，在火星上建立了新的家园！&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《再见，平庸时代》</title><link>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%86%8D%E8%A7%81%E5%B9%B3%E5%BA%B8%E6%97%B6%E4%BB%A3/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%86%8D%E8%A7%81%E5%B9%B3%E5%BA%B8%E6%97%B6%E4%BB%A3/</guid><description>&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="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e7%9c%8b%e8%bf%99%e6%9c%ac%e4%b9%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        《马斯克》这本书中，最后几段介绍了一下经济学家和作者泰勒·考恩的两本书《大停滞》《再见，平庸时代》。《大停滞》讲的是美国这40年发展为何停滞，我当然不太关心这种内容。但是《再见，平庸时代》不是对历史的研究，而是对未来发展的看法，特别是AI对人类生活的影响。&lt;/p&gt;</description><content:encoded>&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="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e7%9c%8b%e8%bf%99%e6%9c%ac%e4%b9%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        《马斯克》这本书中，最后几段介绍了一下经济学家和作者泰勒·考恩的两本书《大停滞》《再见，平庸时代》。《大停滞》讲的是美国这40年发展为何停滞，我当然不太关心这种内容。但是《再见，平庸时代》不是对历史的研究，而是对未来发展的看法，特别是AI对人类生活的影响。&lt;/p&gt;
&lt;p&gt;        对于人类的未来生活是怎么样的，一直比较感兴趣。最近OpenAI也比较火，似乎AI时代就要来了。AI会带给我们生活、工作怎样的改变？社会结构不会不会发生改变？哪些工种会逐渐消失？那些工作会得到收益？   &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%b1%a1%e6%a3%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e4%b8%a4%e6%9e%81%e5%88%86%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e5%ad%a6%e4%b9%a0%e6%88%90%e6%9c%ac" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e8%87%aa%e6%88%91%e5%ad%a6%e4%b9%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        即便是学习成本越来越高，在未来，教育愈发重要。教育体系可能发生变化。由于未来世界时间会更宝贵，而人们也更容易拿到学习资源，人们更倾向于线上学习，自我学习。同时这会导致人的自驱力更加重要。&lt;/p&gt;
&lt;p&gt;        作为一个IT行业的从业者，对于自我学习这件事深有体会。这行业非常内卷，如果不学习基本处于被淘汰的边缘。但是一个非常高效的学习，也会反应在薪水上。我们父辈那个年代靠着分配工作，在一个岗位上可以工作几十年，不会有特别大的变化。那时的人们也只想着工作而不是满脑子自我提升，去考这样那样的证。时代真变了，有多少人像我一样，半夜11点还在写文章&amp;hellip;我甚至对那些毕业后不需要怎么学习的行业感到困惑，是得有多落后。大学毕业不过20多岁，还有几十年的时间可以学习，如果我们就这么停滞不前实在是太奇怪了。我当然不喜欢内卷，但是我更不喜欢原地踱步，特别是在这个坐在凳子上发呆贫富差距就会拉大的年代。&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        文章封面和插图都是AI作画，我只是输入“再见 平庸时代”，然后AI就画出了令人惊叹的图画。我不知道具体哪些行业、哪些职业在未来会消失，但是至少可以看出插图师在AI时代很难生存。&lt;/p&gt;
&lt;p&gt;        人工智能已经侵入到IT领域，作为一个dba来讲，我们哪些工作模式会被替代，这是一个值得思考问题。无论怎样，在这个时代，只有学习才可以保持竞争力，希望我们都不会是那个“消失的棒棒”。&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>我是如何考上武汉大学在职研究生的</title><link>https://lastdba.com/2024/08/13/%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E8%80%83%E4%B8%8A%E6%AD%A6%E6%B1%89%E5%A4%A7%E5%AD%A6%E5%9C%A8%E8%81%8C%E7%A0%94%E7%A9%B6%E7%94%9F%E7%9A%84/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/13/%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E8%80%83%E4%B8%8A%E6%AD%A6%E6%B1%89%E5%A4%A7%E5%AD%A6%E5%9C%A8%E8%81%8C%E7%A0%94%E7%A9%B6%E7%94%9F%E7%9A%84/</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%88%91%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e8%80%83%e5%9c%a8%e8%81%8c%e7%a0%94%e7%a9%b6%e7%94%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ol&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;/ol&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%a8%e6%97%a5%e5%88%b6%e7%a0%94%e7%a9%b6%e7%94%9f%e5%92%8c%e5%9c%a8%e8%81%8c%e7%a0%94%e7%a9%b6%e7%94%9f%e7%9a%84%e5%8c%ba%e5%88%ab" 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%a6%e4%b9%a0%e7%8a%b6%e6%80%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&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%88%91%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e8%80%83%e5%9c%a8%e8%81%8c%e7%a0%94%e7%a9%b6%e7%94%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ol&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;/ol&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%a8%e6%97%a5%e5%88%b6%e7%a0%94%e7%a9%b6%e7%94%9f%e5%92%8c%e5%9c%a8%e8%81%8c%e7%a0%94%e7%a9%b6%e7%94%9f%e7%9a%84%e5%8c%ba%e5%88%ab" 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%a6%e4%b9%a0%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;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%80%83%e8%af%95%e8%8c%83%e5%9b%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;全日制考试压力更大，考试范围基本都是4门：高数，考研英语，政治，专业课.
非全考试压力较小，考试范围是2门：管综（初中数学，逻辑，写作），考研英语.
非全除了英语跟全日制差不多外，管综考试内容比全日制简单很多（后面细说管理类综合联考）&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%a0%94%e7%a9%b6%e6%96%b9%e5%90%91" 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;/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%a4%be%e4%bc%9a%e8%ae%a4%e5%8f%af%e5%ba%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;全日制研究生肯定比非全的认可度高，毕竟门槛高，学习压力更大，主流学历，社会认可要更高。但是非全认可度也是有的，很多学校已明确方针是一视同仁的（明面上）。最重要的一点是，非全日制研究生持有双证（学位证书和学历证书）。&lt;/p&gt;
&lt;p&gt;对于工作方面，就看单位情况了，有些单位招聘要求只要是研究生学历即可，有些可能真写明必须是全日制研究生。但是对于无法脱产提升学历的人来说，非全几乎是唯一途径.
总之，&lt;strong&gt;非全同样是双证，非全认可度 &amp;lt; 全日制认可度&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="#%e5%a6%82%e4%bd%95%e9%80%89%e4%b8%93%e4%b8%9a" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;结合工作性质、发展意向、人民币余额综合考虑..&lt;/p&gt;
&lt;p&gt;人力资源或金融方向或公司高管：MBA&lt;/p&gt;
&lt;p&gt;技术工种或工程管理：MEM&lt;/p&gt;
&lt;p&gt;公务员或公共管理：MPA&lt;/p&gt;
&lt;p&gt;会计：MPAcc。其他还有几个比较冷门自行百度&lt;/p&gt;
&lt;p&gt;从人民币余额角度考虑，每所学校收费不同，但一般不会差别过大。以四川大学为例，MEM一年学费1.5w，MBA一年15w，MPA好像跟MEM差不多。&lt;/p&gt;
&lt;p&gt;像我这样的it人士，囊中羞涩，自我感觉也做不到高管，比较适合MEM。&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%a6%82%e4%bd%95%e9%80%89%e6%8b%a9%e5%ad%a6%e6%a0%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为学习难度相对比较简单，社会认可度也没有全日制高，所以建议选择当地名校。211、985是极其推荐的，找一个自己心仪的学校即可。很多985院校的录取分数线就是国家线，所以个人感觉非211、985的院校报考意义不大，既然分数都一样为什么不选择好一点的学习呢？&lt;/p&gt;
&lt;p&gt;当然有些985有自己的自划线，这个需要自己到学院官网找历年的录取分数线，例如四川大学每年都是自划线，一般超国家线20-30分。&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%8e%e4%b9%88%e8%80%83%e8%af%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="#%e8%80%83%e8%af%95%e5%86%85%e5%ae%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;考试分为初试和复试，初试在12月底，复试在3月份。&lt;/p&gt;
&lt;p&gt;初试既笔试。在报名考试和考点后，在12月底进行考试，一天考完，每场考试3小时。&lt;/p&gt;
&lt;p&gt;复试既面试。少部分学校会加笔试，但是从疫情以后，都是网络面试，很少有面试的时候用笔写什么东西。&lt;/p&gt;
&lt;p&gt;初试内容：（管理类综合联考）



&lt;img src="https://lastdba.com/img/csdn/c920095c8db9.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;复试内容：



&lt;img src="https://lastdba.com/img/csdn/743ea585843c.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%8f%90%e5%89%8d%e9%9d%a2%e8%af%95" 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;/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%a6%82%e4%bd%95%e6%8a%a5%e5%90%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;考研过程中，最重要的2个网址，一个是你要报名的学校官网，另一个就是研招网：中国研究生招生信息网



&lt;img src="https://lastdba.com/img/csdn/85579cc5cd7e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;报考前在硕士目录中查看报考的学校和专业，例如 非全工程管理应如下选择 



&lt;img src="https://lastdba.com/img/csdn/3a5abec906cf.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="#%e8%a6%81%e4%b8%8d%e8%a6%81%e6%8a%a5%e5%9f%b9%e8%ae%ad%e7%8f%ad" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;很多同学都比较关心要不要报培训班的问题。报呢感觉太贵，万一考不上呢？不报嘛不知道咋学或者学的太累。&lt;/p&gt;
&lt;p&gt;这个问题我还是比较有发言权，因为我报了培训班。&lt;/p&gt;
&lt;p&gt;我也是网上看到有培训班，问了一下价格8k，再加上当时存在信息差，不知道考什么，不知道怎么学，不知道怎么报名，不知道报考什么学校，不知道在哪去搜这些信息（马上百度在职研究生，基本全是广告），再加上当时真的很有决心要学习，所以就入了这个坑..&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%9f%b9%e8%ae%ad%e7%8f%ad%e7%bb%99%e4%ba%86%e6%88%91%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;首先给我一堆学习资料，学习方法、真题等等。除了英语词汇我立马拿出背以外，其他东西我基本没动过。真题我也立马打印了 ，那堆真题到考完我也没看过。看上去很有用，实际上淘宝搜索真题一大把正式发版带详细解析的真题，非常好用，也没那么费眼睛。而那个词汇，很奇怪，培训班给我的词汇跟张剑黄皮书词汇对不上，我把培训班词汇背了很久，发现有些真题常见词汇不在词汇本里，后面换了张剑黄皮书词汇本背，感觉好多了。&lt;/p&gt;
&lt;p&gt;处理学习资料外，最重要的就是直播授课，直播课基本都是晚上8-10点，2小时讲课，10分钟答疑。&lt;/p&gt;
&lt;p&gt;直播课还是有用的，特别是逻辑课和数学课，听这2个课基本不需要额外买书全面地学习数学和逻辑基础知识，只需要做课后练习和练题。英语课我基本没听过，基本都是自学的，个人感觉听英语课效率很低，浪费时间，不如多背背单词，多做些阅读题。英语写作课也只听了最后2节，非常有用，后面细讲英语写作（有干货）。最后，不要妄想有问题问老师，这种网课很多人，老师答疑时间就10分钟左右，我提的问题从来没被选中过。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;培训班的好处：&lt;/strong&gt;
学习的方便性。从打工人的角度出发，本身加班就多，回到家累的要死，要我回去把资料铺开像高考一样去学习，太难了。但是如果是授课，我只需要坐在沙发上把直播看完，这eazy很多
节省时间。不需要费周折地制定计划并在期间不断调整学习计划，听课的效率也比把厚厚的一本书自己看完要来的更容易。从本质上讲，培训班就是拿钱买时间。&lt;/p&gt;
&lt;p&gt;同学的学习状态良好会激励你学习，你不会是孤单一个人学习，完全不知道别人学的怎么样。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;培训班的坑：&lt;/strong&gt;
培训班参差不齐。我当时报考的shangdejigou，报的时候没有调查过这家机构，确实很一般。他们有的班是协议形的，没考上的话会退费，但是协议里有坑，都没退成。我们群里有很多闹退费的。还有个人信息泄露的问题，基本所有学员都接到过退费诈骗电话，连我这种考上的都接了5、6个诈骗电话了。&lt;/p&gt;
&lt;p&gt;老师素质参数不齐。有的老师讲的好，有的老师感觉像是摸鱼的，甚至有些讲解完全就是误人子弟。我那个班就是数学和逻辑老师讲的特好，英语垃圾，写作误人子弟&amp;hellip;&lt;/p&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;足够的决心。既然已经交钱了，就不要打水漂，也不建议报退费的班给自己留后路&lt;/li&gt;
&lt;li&gt;足够的资金。线上培训班几大千起步，我这个8k可以参考。线下会更贵，但是有老师线下辅导&lt;/li&gt;
&lt;li&gt;无法填补信息差。信息差可能会导致无法自我规划学习计划。如果是信息差导致报班，我建议多看看别人的学习计划，b站成功的up案例。最大的信息来源一定是学校官网&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="#%e5%88%9d%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;在初试结束之前，只需要准备初试即可&lt;/strong&gt;。一般来说复试内容在初试完后再准备即可。&lt;br&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%a6%82%e4%bd%95%e5%87%86%e5%a4%87%e5%88%9d%e8%af%95%e5%ad%a6%e4%b9%a0%e8%ae%a1%e5%88%92" 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;每个人情况情况是不一样的，先讲讲我的学习计划，可以参考我的定制计划的方式，和学习方式。因为学习压力没有那么大（相比全日制），非常建议从7、8月份开始准备学习，过晚时间不够，过早容易懈怠，整个学习时间为5-6个月。但是如果你的英语确实有够烂，再多提前几个月去背单词。&lt;/p&gt;
&lt;p&gt;我的个人条件如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;时间不够充足，经常加班到晚上9点，周末一般都是双休。上下班地铁，双向共2小时。&lt;/li&gt;
&lt;li&gt;数学基本忘精光，逻辑从来没碰过，语文写作从小稀烂，英语词汇量还行，阅读没问题，英语写作完全不会。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结合学习压力和个人条件，我需要这样制定计划：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;背单词。英语肯定是最花时间的，需要长时间持续性地背单词，在所有学习开始之前，背英二单词。因为早上记忆力最好，我每天在上班的地铁上背单词，周末早上也背单词。时间从8月份开始，一直到初试。&lt;/li&gt;
&lt;li&gt;英语阅读。其实只要把单词背下来，阅读很容易理解。英二的长难句并不多，能认识所有单词，阅读肯定没问题。但是个人比较爱好英语阅读，我计划了每天的英语原著阅读。不能说用处大，也不是完全没用，就当是辅助考试。重要的是，爱好更容易培养习惯。&lt;/li&gt;
&lt;li&gt;数学和逻辑，其实学习难度差不多，我虽然完全不会，但是学起来较为简单（知识点是简单的，考试是另一个样子这里先不谈）。我会在下班晚上20:00 -22:00点学习数学或逻辑（主要是听课，没有课的可以自己买资料学习），这个也是长时间学习，前期学习知识点，后期练题。因为不是每天都能正常下班，所以有时候需要利用下班地铁时间和中午1小时午休时间，把数学和逻辑的每日学习任务完成。（千万不能拖，拖一次就会累积很多）&lt;/li&gt;
&lt;li&gt;中文写作。在考前一个月，也就是11月底12月初准备即可。看下作文资料，自己试着写，不用想的要多完美，主要是把主题含义表达清楚。相信我，考试的时候你绝对是用的狂草在写作。&lt;/li&gt;
&lt;li&gt;英语写作。在考前一个月，准备即可。切记，千万千万不要背范文，不仅非常难背，而且根本无法套用。考前背2-3个模板即可，用模板联系历年真题，只需要替换单词即可，不会发生提笔一个单词写不出的情况。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，我的周计划如下：



&lt;img src="https://lastdba.com/img/csdn/8b233995a8b3.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;这样安排感觉比较合适自己，既充分利用了碎片化时间，也充分利用了周末。前3-4个月打基础，英语的基础是单词，逻辑和数据的基础是知识点，每周工作日的学习，可以在周末汇聚复习和练习。后1-1.5个月主要就是写作和找做真题的感觉。&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%a8%e8%8d%90%e7%9a%84%e5%ad%a6%e4%b9%a0%e8%b5%84%e6%96%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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;逻辑：中公《逻辑轻松通关》，历年真题解析&lt;/li&gt;
&lt;li&gt;管综写作：找个销量高的吧，都不是很好用。写作不用学太精&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;不要买练习题，直接买真题做&lt;/strong&gt;，现有的练习题质量跟真题完全比不了。英语不需要买练习题，直接买真题即可。数学和逻辑除了基础学习的一些自带练习题外，也不要买额外的练习题。我也做过一小段时间的数学练习题，很花时间，效果并不好。数学和逻辑主要还是要把基础打好，把知识点学齐，然后做真题看解析即可。总之，沉浸式学习时间（比如周末）只需要做真题，真题做近20年的即可，做完然后重新做一遍（20份真题，周末2天也就做2套，要2个多月才能做完一轮，重新做的时候前面的题已经忘的差不多了）。&lt;strong&gt;最近两年的2套真题一直都不要做，留着考前2周掐表自我模拟&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="#%e8%8b%b1%e8%af%ad%e5%ad%a6%e4%b9%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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%8d%95%e8%af%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;早上雷打不动地背单词（在地铁上效果非常好···）。
百词斩——有些小伙伴喜欢用百词斩，我前期也在使用百词斩，但是我感觉效果不好，它是全量单词，背一年可能都循环不了一遍，前面背的早忘了，所以后期我没有用这个软件。
我个人强烈推荐我背单词的办法。&lt;/p&gt;
&lt;p&gt;每个人的单词量是不一样的，刚开始的时候，必须把所有单词全部过一遍（考研词汇大概5000个左右），把不认识的拎出来写在单词本上。由于拿着单词本在地铁上背会略显尴尬，所以我放在手机里。&lt;/p&gt;
&lt;p&gt;我专门有一个单词本相册：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/63e6fcbbd3e9.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;每次背的时候，点开，放大，相当于蒙住注释背单词。



&lt;img src="https://lastdba.com/img/csdn/63e6b5373162.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;这样循环背诵，刚开始我每天背2页，每天前进1页，后面每天背4页，每天前进4页。无论如何，循环背，背到蒙住注释就知道单词的含义。有些单词容易混淆的可以加在单词本里再拍照更新相册。&lt;/p&gt;
&lt;p&gt;在我初试前，这些单词我已经背了6、7遍了，基本上除了超纲单词，我没有不认识的。&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="#%e9%98%85%e8%af%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;英语总分100分，阅读能力分数占比=完型填空10分+阅读理解40分+新题型阅读10分=60分。英语能力再烂不能烂阅读理解能力。我的阅读能力基本上都是靠每日的外刊阅读，比如 爱阅读、考研英语外刊 。每天花20分钟左右，学习压力也不大（其实主要是单词，单词认识，句子就好理解）。&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;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%86%99%e4%bd%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;写作分为小作文（书信或通知，10分），大作文（材料分析文——柱状图饼状图分析，15分）&lt;/p&gt;
&lt;p&gt;再次提醒，不要背范文。考前我专门买了一本写作的书，背了10篇范文，真的很难很难很难背，而且难套用，范文背完，我第一次做英语写作题，毫不夸张我一个字都写不出来。&lt;/p&gt;
&lt;p&gt;我学习的培训课程里，对我来说最最有价值的，就是英语模板，我按照模板把历年的英语写作全部做了一遍，全部都能套用。要替换的单词不超过20个，会写简单句即可。模板如下：&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;Dear  Sir or Madam,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    I am an undergraduate who majos in Applied English in this/a university.I am writing this letter &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; the purpose of doing sth.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    1.It,first an formost,is my idea that not only ... but also
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    2.Then more importantly,so ... that...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    3.The last on I must point out is that 简单句,which could be accepted by the majority of 人/.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    So It is the very moment &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; me to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; ...,And I am looking forward to your reply.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;                                                                                          yours truly,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;                                                                                            xxx.                                                                        &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中 doing sth包含：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;1.感谢信:expressing my genuine gratitude &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; your kind help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2.建议信:making some suggestions concerning sth.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3.投诉信:making my complaints concerning sth.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4.祝贺信:show my sincere congratulations to you because 句子
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5.道歉信:offer my sincere apology to you because 句子
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.邀请信:invite you to participate in 活动 on behalf of 某人/组织
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7.通知信:have 某人 informed that 句子&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;                                               Notice
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    In an effort to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; sth,I woud like to offer you some detailed information about it.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    The 活动 will be held in the school auditorium at &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; p.m.,next Saturday,December 28th and the requirements &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; sth. are listed as follows.
&lt;/span&gt;&lt;/span&gt;&lt;span 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;    If you have any questions,please feel free to send on email to 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;studentsunion@123.com or call 1234567.We are looking forward to your participation.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;大作文基本只有柱状图和饼状图的分析，图例只分为 比大小和比趋势 。比大小和比趋势只有首段不一样，后面2段是一样的。&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:#f92672"&gt;(&lt;/span&gt;比大小首段&lt;span style="color:#f92672"&gt;)&lt;/span&gt;The diagram clearly shows/illustrates/d that 句子/词组&lt;span style="color:#f92672"&gt;(&lt;/span&gt;the purposes of/attitudes toward/the proportions of&lt;span style="color:#f92672"&gt;)&lt;/span&gt; among participants/respondents in a certain college.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Based on the data offered,one can distinctly see that 对象1 ranks the first/highest among all the categories,accounting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; 数据1.Next are 对象2 and 对象3 with 数据2 and
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;数据3 respectively ,while 对象4 only constitutes 数据4.
&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;The diagram clearly illustrates how 话题 changed during the past several years.Based on the data provided,one can distinctly see that the number of 对象1 rose/fell significantly/slightly/gradually from 数据 in 年 to 数据 in 年,while that the number of 对象2 experienced a gradual/significant increase/decrease during the same period,reaching 数据 in 年.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    From my standpoint,there are two fundamental factors that are responsible &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; this scence.To begin with,the first contributing factor is that 句子.In addition,another important factor that cannot be ignored is that 句子.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    In view of the analysis above,we can conclude that it is of little surprise to see this phenomenon in the current era.Therefore,it can be predicted that 名词词组/动词ing will still take up a large share in the future.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;作文不背模板靠自己写非常难，背模板拿个超高分数比较难，但是拿70-80%的分数是没问题的，而且前提投入基本为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="#%e6%95%b0%e5%ad%a6%e5%ad%a6%e4%b9%a0%e9%80%bb%e8%be%91%e5%ad%a6%e4%b9%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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%95%b0%e5%ad%a6%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e16c5ab94d30.png" alt="在这里插入图片描述" /&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="#%e9%80%bb%e8%be%91%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/bc084fe7654f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt; 数学和逻辑都是选择题，没有什么好说的，前期主要学习知识点，后期需要提升做题速度。&lt;/p&gt;
&lt;p&gt;数学和逻辑的知识点非常多的，前期学习时间需要花3-4个月，每天学习2-3个小时，把知识点全部学会。知识点学完后拿真题练习看解析。最后1个月恰表练习，提高做题速度，数学做题时间不超过70分钟，逻辑做题时间不超过60分钟。&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%ad%e6%96%87%e5%86%99%e4%bd%9c%e5%ad%a6%e4%b9%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;管综作文分为 论证有效性分析和论说文。&lt;/p&gt;
&lt;p&gt;论证有效性分析就是抬杠，找本写作书看看，并不难写。论证有效性分析需要在一大段材料找找出材料推理问题所在，写的时候找4个问题点即可。没有学过的话可能找不太到，学过后找4个问题点还是比较简单的。不用把问题写的特别明确，比如这个问题是以偏概全、偷换概念、非黑即白等等，把它写成”xxx推不出xxx“即可。&lt;/p&gt;
&lt;p&gt;论说文主要是对一小段材料做出自己的理解。论说文需要注意 主题 别写歪了，刚开始找主题也挺难的，多看几个论说文材料，找找感觉，基本能找到主题在哪。论说文一般写作结构为总分总，建议以 “个人-企业-国家”为思路来写（总-个人-企业-国家-总，共5段），找几个自己拿手的材料往里面套用。一些同学觉得自己作文能力强，会以其他思路来写议论文，我个人当然是非常佩服的。因为写作时间是非常有限的，除非天赋异禀思路非常快，不然还是建议用套路来写，&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="#%e8%80%83%e8%af%95%e6%97%b6%e7%9a%84%e5%81%9a%e9%a2%98%e8%a7%84%e5%88%92" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;是的，做题也得规划，100%相信我，管综你做不完。管综是我平生考过的，时间最仓促的考试，你知道这些题你会，但是你没有时间去运算。&lt;/p&gt;
&lt;p&gt;初试考试时，上午管综3小时，下午英语3小时。&lt;/p&gt;
&lt;p&gt;英语考试时长3小时，内容较少，也没有需要反复演练的点，做题时间是完全足够的。我当时考完时间还剩了50分钟，提前交卷走了。&lt;/p&gt;
&lt;p&gt;管综3小时，完全不够。我在考前自我模拟的时候，基本都是4小时才做完的。考试时，数学只要有做题时间超过3分钟，直接跳过，感觉运算量大，直接跳过。逻辑题，根本无法用平时做题的思路去做，快速读完题（逻辑题文字巨多）看选项，感觉对的就勾上，需要运算的逻辑题暂时放弃，后面有时间在做。写作题看完题目直接写，能写多快写多快（2篇写作总共不能超过1小时），每省2分钟，就可能拯救一道选择题。&lt;/p&gt;
&lt;p&gt;选择题可以不用做完（答题卡要涂完哈），但是写作一定要写完，所以做题顺序很重要。很多人一般上来都直接写作文，然后做选择题。我是先做数学题，然后写作文，然后逻辑题。反正总之，不要把写作放在最后做。真实考试时，两篇作文完成时间不能超过55分钟，总共1500字，还要阅读材料和构思，去做一次就知道时间是多么不够。&lt;/p&gt;
&lt;p&gt;最后20分钟，涂答题卡，涂完再继续做题。&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%a4%8d%e8%af%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="#%e5%a4%8d%e8%af%95%e7%9a%84%e5%9f%ba%e6%9c%ac%e4%bf%a1%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果你如愿过了国家线或者学院自划线，那么你已经完成了90%的进度。剩下10%既复试。复试也是有淘汰率要求的（国家强制要求），一般在淘汰率在70-80%左右。这个淘汰率一定存在，所以每年一定有人复试被刷，如果你不准备，那么极有可能就是你。讲个笑话，我复试四川大学被刷~&lt;/p&gt;
&lt;p&gt;复试时间：每年3月中旬到3月底&lt;/p&gt;
&lt;p&gt;成绩公布时间：3月中旬&lt;/p&gt;
&lt;p&gt;考试内容：英语口语，专业课，综合面试，政治（川大政治开卷，不用准备，武大政治闭卷笔试···）&lt;/p&gt;
&lt;p&gt;疫情以后复试都是网络面试，没有笔试环境，专家提问学习回答的模式。&lt;/p&gt;
&lt;p&gt;也就是说你有3个月的时间来准备复试。而恰巧初试考完是12月底，加上成绩还没出，再加上2月份过年，其实大部分人都是成绩公布的时候开始准备。已我这个反面教材为例，我是3月21日接到复试通知，复试时间是3月27日，我就准备了6天时间，其中还要考英语口语和我从没接触过的工程管理···，所以很尴尬，考官英文我一个没答上来，专业课题目一个没答上来，复试被刷。&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%bd%91%e4%b8%8a%e8%b0%83%e5%89%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;当我知道四川大学复试没通过后，我的情绪跌入谷底。但是，柳暗花明又一村，调剂是我的救命稻草，当我在找调剂学校时，发现了武汉大学。&lt;/p&gt;
&lt;p&gt;研招网专门有个调剂窗口，给予复试被刷的同学再3次面试的机会。调剂可以填3个志愿，也就是可以填3个学校。由于每个学校复试时间复试要求都不一样，全部准备是很难的。我主要就是准备武汉大学的调剂。调剂当然也是要复试的，其实就是没有招满学生的院校把复试再走一遍，给那些首批没有录取上的同学再一次的机会。&lt;/p&gt;
&lt;p&gt;调剂窗口：3月底到4月初&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%a6%82%e4%bd%95%e5%87%86%e5%a4%87%e5%a4%8d%e8%af%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;复试也是非常卷的，跟我一样懒的人不会在少数···但是无论如何，已经付出了大半年，不能就这么打水漂了（我是差点真打水漂了···）。像我这种非专业学生，复试最难的就是英语口语和专业课。从成绩公布到复试，大概只有1周时间来准备（还要上班！），所以从头学肯定是来不及的，以我的经验，下面的学习办法的重要性依次递减&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;找学长学姐要历年复试资料（低调，复试资料外传是违规的）和老师上课资料。找找有没有人认识的在那个院校的，或者贴吧找组织，找群&lt;/li&gt;
&lt;li&gt;B站搜 考研复试常问的问题。把问题总结总结，背一背。&lt;/li&gt;
&lt;li&gt;买学院推荐的参考书（一般是教学资料）。很厚，看不完。&lt;/li&gt;
&lt;/ul&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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;22年考研初试国家线是185，我初试成绩210（英语80，管综130）。附上我的复试通过通知^_^



&lt;img src="https://lastdba.com/img/csdn/afd22229a49a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;祝被社会毒打仍不死心的 打工人学子，考研一切顺利，上岸！！！&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>HikariCP连接池初识</title><link>https://lastdba.com/2024/08/12/hikaricp%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%88%9D%E8%AF%86/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/hikaricp%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%88%9D%E8%AF%86/</guid><description>&lt;h2 class="relative group"&gt;HikariCP的简单介绍
 &lt;div id="hikaricp的简单介绍" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hikaricp%e7%9a%84%e7%ae%80%e5%8d%95%e4%bb%8b%e7%bb%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;hikari-光，hikariCP取义：像光一样轻和快的Connetion Pool。这个几乎只用java写的中间件连接池，极其轻量并注重性能，HikariCP目前已是SpringBoot默认的连接池，伴随着SpringBoot和微服务的普及，HikariCP 的使用也越来越多。&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;HikariCP的简单介绍
 &lt;div id="hikaricp的简单介绍" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#hikaricp%e7%9a%84%e7%ae%80%e5%8d%95%e4%bb%8b%e7%bb%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;hikari-光，hikariCP取义：像光一样轻和快的Connetion Pool。这个几乎只用java写的中间件连接池，极其轻量并注重性能，HikariCP目前已是SpringBoot默认的连接池，伴随着SpringBoot和微服务的普及，HikariCP 的使用也越来越多。&lt;/p&gt;
&lt;p&gt;在hikariCP github首页就放了一篇性能对比：



&lt;img src="https://lastdba.com/img/csdn/3da983db32ca.png" alt="在这里插入图片描述" /&gt;
（https://github.com/brettwooldridge/HikariCP-benchmark）&lt;/p&gt;
&lt;p&gt;看上去好像是碾压一众数据库连接池中间件。然而这个性能对比的有点老了，而且没有阿里自研的国产巅峰连接池druid的性能对比。我稍微看了下&lt;a href="https://github.com/alibaba/druid" target="_blank" rel="noreferrer"&gt;druid&lt;/a&gt;的github首页，star比hikariCP还多一点，druid在功能性上明显比hikariCP强。至于两者的性能谁更好，还引发过&lt;a href="https://github.com/brettwooldridge/hikaricp/issues/232" target="_blank" rel="noreferrer"&gt;一次大佬间的口水战&lt;/a&gt;，目前没有看到有严格的性能对比报告。不过这不是我们这篇文章的重点···这篇文章只是为了稍微了解下hikariCP。&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%87%a0%e4%b8%aa%e8%bf%9e%e6%8e%a5%e6%b1%a0%e5%8f%82%e6%95%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;minimumIdle&lt;/td&gt;
 &lt;td&gt;这个属性控制着HikariCP尝试在连接池中维持的空闲连接的最小数量。如果空闲连接的数量下降至此值以下，并且连接池中的总连接数少于maximumPoolSize，HikariCP将尽最大努力快速而高效地添加额外的连接。然而，为了达到最大性能和对高峰需求的响应性，我们推荐不设置这个值，而是让HikariCP充当一个固定大小的连接池。默认值：与maximumPoolSize相同。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;maximumPoolSize&lt;/td&gt;
 &lt;td&gt;此属性控制池所能达到的最大大小，包括空闲和正在使用的连接。基本上，此值将决定到数据库后端的实际连接数的上限。合理的值最好由您的执行环境确定。当池达到此大小且没有可用的空闲连接时，调用 getConnection() 将会阻塞，直至 connectionTimeout 毫秒后超时。默认值：10&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;maxLifetime&lt;/td&gt;
 &lt;td&gt;此属性控制池中连接的最大生命周期。正在使用中的连接永远不会被弃用，只有当它被关闭时才会被移除。为了避免池中发生大规模的连接消失，该属性会对每个连接适用轻微的负衰减。我们强烈推荐设置此值，并且应该比任何数据库或基础设施强加的连接时间限制短几秒。值为0表示无最大生命周期（无限生命周期），当然，这受到idleTimeout设置的约束。允许的最小值是30000毫秒（30秒）。默认值：1800000（30分钟）。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;idleTimeout&lt;/td&gt;
 &lt;td&gt;此属性控制连接在池中允许空闲的最大时间。此设置仅在minimumIdle被定义为小于maximumPoolSize时适用。一旦池达到minimumIdle连接数，空闲连接不会被回收。连接是否被视为空闲并回收，其最大变化范围为+30秒，平均变化范围为+15秒。一个连接在此超时前永远不会被视为空闲并回收。值0表示空闲连接永远不会从池中移除。允许的最小值是10000毫秒（10秒）。默认值：600000（10分钟）。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;keepaliveTime&lt;/td&gt;
 &lt;td&gt;此属性控制 HikariCP 将多频繁地尝试保持连接active，以防止它因数据库或网络基础设施而超时。这个值必须小于 maxLifetime 的值。&amp;ldquo;keepalive&amp;quot;操作仅会发生在空闲连接上。允许的最小值是30000毫秒（30秒），但最理想的值是在几分钟的范围内。默认值：0（禁用）。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;keepaliveTime参数的设置应低于数据库空闲连接超时时间、TCP空闲连接超时时间以及一切其他设施的空闲超时时间。对于PostgreSQL来说，hikariCP的keepaliveTime参数应设置为小于PG库&lt;code&gt;idle_in_transaction_session_timeout&lt;/code&gt;的时间。&lt;/p&gt;
&lt;p&gt;很明显，maximumPoolSize代表连接到数据库中的最大连接数。当然一般来说，真实场景中数据库中的连接数不会一直保持maximumPoolSize，因为应用不可能从始至终都是最高负荷运行。即使经过一个请求高峰期，根据idleTimeout或者maxLifetime的设置，那些空闲的连接经过一段时间后应该被释放。为了保证数据库的可用性，这个值应该设置为比数据库最大连接数小一些。比如PostgreSQL数据库，maximumPoolSize参应设置为小于PG库的&lt;code&gt;max_connections&lt;/code&gt;。这个参数还有调优空间，我们下面会提及。&lt;/p&gt;
&lt;p&gt;minimumIdle是最小空闲连接数。例如，如果minimumIdle=100，数据库的active会话有10个，那么理论上数据库中的总连接数应该是100+10个。因为有可能有连接风暴的情况，真实的数据库连接应该比active+minimumIdle略多一点，但肯定小于maximumPoolSize。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;为什么数据库连接数远大于minimumIdle&lt;/em&gt;？&lt;/p&gt;
&lt;p&gt;理论上数据库总连接数只应该略大于minimumIdle，但是经过我实际观察连接池多节点的情况，哪怕数据库活跃连接只有10几个，数据库总连接数却远大于minimumIdle。观察pg_stat_activity的min(backend_start)、min(state_change)，基本保持在maxLifetime左右，说明连接回收是有作用的。看上去新请求总喜欢启用新连接，而不是直接拿已有的idle连接用。个人猜多节点部署是原因之一，每个节点minimumIdle很低，也可能存在某些组件上的节点请求要多一点，瞬时请求数超过了minimumIdle从而创建了新的连接。第二，这跟maxLifetime参数也有关系，maxLifetime的目的是为了旋转连接，释放那些一直在用的连接，这样就存在那些使用过的链接需要一段时间来释放，并且最好不要再使用了，以免延长释放周期。&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%9e%e6%8e%a5%e6%b1%a0%e5%a4%a7%e5%b0%8f%e8%ae%be%e7%bd%ae" 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="#%e8%bf%9e%e6%8e%a5%e6%95%b0%e8%bf%87%e5%a4%9a%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;p&gt;例如oracle的连接数对性能的影响，参考&lt;a href="https://www.youtube.com/watch?v=_C77sBcAtSQ" target="_blank" rel="noreferrer"&gt;这个视频&lt;/a&gt;。当资源配置、jdbc并发都不变的情况下，连接数从2048下降到1024个，请求响应时间下降一半；如果连接数调整到96个，响应时间下降几十倍！！&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%9e%e6%8e%a5%e6%95%b0%e8%ae%be%e7%bd%ae%e4%b8%ba%e5%a4%9a%e5%b0%91%e6%89%8d%e5%90%88%e9%80%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Unless you have a database server that has 1000 cores, it is very unlikely that you really want a maximumPoolSize of 2000.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;除非你的数据库有1000C，不然你不应该有2000个连接。&lt;/p&gt;
&lt;p&gt;最初始的情况下，数据库连接数应设置为cpu数，这样就能达到cpu的最大性能模式。但是这不是真实的。因为数据库的消耗不仅在cpu，也在磁盘和网络（也有内存、但相对影响不大）。例如，磁盘的读写也需要时间，cpu需要等待磁盘返回数据才可以进行下一步动作。在IO等待的这段时间（有可能时间很长），cpu最好是不要闲着，而是给其他进程使用。所以，基于磁盘等设备的等待时间，数据库连接数最好是高于cpu个数。&lt;/p&gt;
&lt;p&gt;由于SSD等磁盘性能的提升，磁盘访问的速度是非常快的，也就是说IO等待时间下降，意味着连接数应该调整得更低。&lt;/p&gt;
&lt;p&gt;调低了不能压榨CPU，调太高数据库性能损耗，那么到底调整到多少合适呢？hikariCP给出了这么一个公式&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;connections = ((core_count * 2) + effective_spindle_count)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其中core_count不应该计算超线程数；effective_spindle_count为主轴数，如果活动数据集完全被缓存，那么effective_spindle_count为零，随着缓存命中率的下降，它应该接近于实际的主轴数量。对应SSD还没有想过公式，不过可以肯定小于以上的最大值。当然这些都是理论值，实际情况要比这个更复杂，比如长连接问题，具体可参考&lt;a href="https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing" target="_blank" rel="noreferrer"&gt;连接池大小相关知识。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;即使前端有10000个用户，连接池也不可能是10000个，即使是1000也太多了，需要一个更小的连接数，让其余的请求在连接池中等待，发挥数据库及其CPU的最佳性能才是最好的方式，参考连接数设置如上公式所示。&lt;/p&gt;

&lt;h2 class="relative group"&gt;fixed pool
 &lt;div id="fixed-pool" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fixed-pool" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;fixed pool是HikariCP的作者Brett Wooldridge的一个理念，是为了解决连接风暴问题。在minimumIdle参数解释中已经提及fixed pool：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;为了达到最大性能和对高峰需求的响应性，我们推荐不设置minimumIdle，而是让HikariCP充当一个固定大小连接池（&lt;em&gt;fixed size&lt;/em&gt; connection pool）。默认值：与maximumPoolSize相同。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;把minimumIdle=maximumPoolSize就是fixed size connection pool。minimumIdle的默认值就等于maximumPoolSize。&lt;/p&gt;
&lt;p&gt;其实早在2014年，Brett Wooldridge就提到了这个概念，参考&lt;a href="https://www.postgresql.org/message-id/DF286FBF-D1F5-4A10-88AD-EDD5D2AFAABD%40gmail.com" target="_blank" rel="noreferrer"&gt;PG社区邮件&lt;/a&gt;。这段话很重要，我将逐字翻译：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;根据我的经验，即使是维护最小空闲连接数的池，在响应突发需求时也是有问题的。如果你有一个最大30个连接的池，并且有一个最小10个空闲连接的目标，突发的需求需要20个连接意味着连接池可以立即满足10个，但随后要尝试在应用程序申请连接时间到达connectionTimeout之前建立另外10个连接。这反过来在数据库上产生了突发需求，不仅减慢了建立连接本身，也减慢了实际上可能会将连接返回给连接池的事务。&lt;/p&gt;
&lt;p&gt;现在，如果你的峰值是100个连接，你的中位数是50个，这并不重要。但我知道不少工作负载的峰值是1000，中位数是25，在这种情况下你会想要逐渐减少空闲连接。&lt;/p&gt;
&lt;p&gt;最终我们采用了一个maxPoolSize + minIdle模型，默认情况它俩相等（fixed pool）。&lt;/p&gt;
&lt;p&gt;虽然我不怀疑存在这样的工作负载（1000个活动连接），如果有人真的这么做了，我很想听听他们的理由。除非他们有超过128个CPU核和固态存储，否则基本上就是在白费功夫。&lt;/p&gt;
&lt;p&gt;这也意味着，即使连接池的大小是固定的，你也想要旋转（rotate in and out）实际的会话，这样它们就不会无限期地挂着最大虚拟内存。&lt;/p&gt;
&lt;p&gt;我们确实是这样做，有一个maxLifeTime设置来旋转这些连接。&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;在真实场景中，fixed pool对连接风暴影响的保护是可见的。fixed pool下，数据库的瞬时active连接突增，数据库的idle链接数下降，但数据库的总连接数不变，请求响应耗时影响不大。如果把maximumPoolSize设置为比minimumIdle大的一个值，连接风暴会造成瞬间产生很多新会话，而新会话的连接是非常消耗资源的，这明显增加了请求的响应时间。&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%9e%e6%8e%a5%e6%b3%84%e9%9c%b2%e6%a1%88%e4%be%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;由于本人不是连接池的专家，这里只是把最近找到的连接泄露资料小小汇总下。&lt;/p&gt;
&lt;p&gt;连接泄露有如下现象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;“Connection is not available” exception。连接泄露，连接打满或者数据库因为active会话过度响应不过来了，新的请求会因为超过&lt;code&gt;connectionTimeout&lt;/code&gt;时间而报错&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Growth of active connections。数据库监控可以明显看到活动会话上涨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Application logs。应用日志也可以看到很多连接请求，包括活跃会话信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Database views and logs。&lt;code&gt;pg_stat_activity&lt;/code&gt;可以看到所有的会话状态和具体的sql，以及在log中可以看到新连接认证登录信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HikariCP leak detection。需要打开&lt;code&gt;leakDetectionThreshold&lt;/code&gt;，HikariCP可以检测链接泄露，这个参数默认是关闭的&lt;/p&gt;
&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;li&gt;善于debug、trace等hikariCP设置&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;leakDetectionThreshold&lt;/code&gt;参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可能的原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Misuse of streaming responses;&lt;/li&gt;
&lt;li&gt;Misuse of raw connections;&lt;/li&gt;
&lt;li&gt;Prolonged operations within &lt;code&gt;@Transactional&lt;/code&gt; method (such as network invocation).&lt;/li&gt;
&lt;li&gt;配置错误，&lt;a href="https://mkyong.com/jdbc/hikaripool-1-connection-is-not-available-request-timed-out-after-30002ms/" target="_blank" rel="noreferrer"&gt;参考&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vitual thread，&lt;a href="https://github.com/brettwooldridge/HikariCP/issues/2151" target="_blank" rel="noreferrer"&gt;参考&lt;/a&gt;&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;p&gt;&lt;a href="https://github.com/brettwooldridge/HikariCP" target="_blank" rel="noreferrer"&gt;https://github.com/brettwooldridge/HikariCP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/brettwooldridge/HikariCP/issues/2148" target="_blank" rel="noreferrer"&gt;https://github.com/brettwooldridge/HikariCP/issues/2148&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing" target="_blank" rel="noreferrer"&gt;https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.oracle.com/opal/post/always-use-connection-pools" target="_blank" rel="noreferrer"&gt;https://blogs.oracle.com/opal/post/always-use-connection-pools&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mkyong.com/jdbc/hikaripool-1-connection-is-not-available-request-timed-out-after-30002ms/" target="_blank" rel="noreferrer"&gt;https://mkyong.com/jdbc/hikaripool-1-connection-is-not-available-request-timed-out-after-30002ms/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://medium.com/@eremeykin/how-to-deal-with-hikaricp-connection-leaks-part-1-1eddc135b464" target="_blank" rel="noreferrer"&gt;https://medium.com/@eremeykin/how-to-deal-with-hikaricp-connection-leaks-part-1-1eddc135b464&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://medium.com/@eremeykin/how-to-deal-with-hikaricp-connection-leaks-part-2-847a9629627f" target="_blank" rel="noreferrer"&gt;https://medium.com/@eremeykin/how-to-deal-with-hikaricp-connection-leaks-part-2-847a9629627f&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>ORDER BY limit 10比ORDER BY limit 100更慢</title><link>https://lastdba.com/2024/08/12/order-by-limit-10%E6%AF%94order-by-limit-100%E6%9B%B4%E6%85%A2/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/order-by-limit-10%E6%AF%94order-by-limit-100%E6%9B%B4%E6%85%A2/</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%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg数据库中执行sql时，ORDER BY limit 10比ORDER BY limit 100更慢&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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e5%88%86%e6%9e%90" 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:#66d9ef"&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;*&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; cl.ITEM_DESC &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tablelzl2 cl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; item_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; cl.ITEM_NO&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;item&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablelzl1 RI
&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; RI.column1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;AAAA&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;AND&lt;/span&gt; RI.column2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;applyno20231112&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;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RI.column3 &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;10&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Limit (cost=0.43..1522.66 rows=10 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan Backward using idx_tablelzl1_column3 on tablelzl1 ri (cost=0.43..158007.45 rows=1038 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((column1)::text = &amp;#39;AAAA&amp;#39;::text) AND ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;主表没有走到column2索引，而是走column3排序字段索引的Index Scan Backward，scan index的cost非常高，而最终的cost比较低，实际执行需要9s
如果把limit 10改成limit 100，执行计划正常：&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%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg数据库中执行sql时，ORDER BY limit 10比ORDER BY limit 100更慢&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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e5%88%86%e6%9e%90" 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:#66d9ef"&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;*&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; cl.ITEM_DESC &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tablelzl2 cl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; item_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; cl.ITEM_NO&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;item&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablelzl1 RI
&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; RI.column1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;AAAA&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;AND&lt;/span&gt; RI.column2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;applyno20231112&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;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RI.column3 &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;10&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Limit (cost=0.43..1522.66 rows=10 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan Backward using idx_tablelzl1_column3 on tablelzl1 ri (cost=0.43..158007.45 rows=1038 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((column1)::text = &amp;#39;AAAA&amp;#39;::text) AND ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;主表没有走到column2索引，而是走column3排序字段索引的Index Scan Backward，scan index的cost非常高，而最终的cost比较低，实际执行需要9s
如果把limit 10改成limit 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:#66d9ef"&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;*&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; cl.ITEM_DESC &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tablelzl2 cl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; cl.ITEM_NAME &lt;span style="color:#f92672"&gt;=&lt;/span&gt; RI.MANUAL_SIGN &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; cl.ITEM_NO&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;manualSign&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;manualSign&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablelzl1 RI
&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; RI.column1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;AAAA&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;AND&lt;/span&gt; RI.column2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;applyno20231112&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;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RI.column3 &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;100&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-text" data-lang="text"&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Limit (cost=2632.28..3162.78 rows=100 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Result (cost=2632.28..8138.87 rows=1038 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Sort (cost=2632.28..2634.87 rows=1038 width=474)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort Key: ri.column3 DESC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using idx_cri_column2 on tablelzl1 ri (cost=0.43..2592.61 rows=1038 width=474)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((column1)::text = &amp;#39;AAAA&amp;#39;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(10 rows)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;子查询执行计划不变，主表走到column2单列索引，回表后排序再limit，执行非常快。
不仅是limit，如果原sql仅更换column2的值，执行计划也正常。也就是说这个生产的sql只有极个别的column2的值时执行计划是异常的。&lt;/p&gt;
&lt;p&gt;执行计划分析：
子查询前后没变可以不用分析，主要是索引选择上的不同。column2是过滤字段，column3是排序字段，两个执行计划分别选择了这2个字段的索引。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异常的limit 10执行计划：&lt;em&gt;反向扫描排序字段索引-&amp;gt;回表 -&amp;gt;limit&lt;/em&gt;。因为不需要额外排序，反向扫描索引时找到limit个数据就可以不用继续扫描了；扫描排序字段索引的预估代价非常高，最上层的limit最终代价预估很低。&lt;/li&gt;
&lt;li&gt;正常的limit 100执行计划：&lt;em&gt;访问过滤字段索引-&amp;gt;回表 -&amp;gt;以排序字段排序 -&amp;gt;limit&lt;/em&gt;。因为要排序，需要把符合条件的所有索引条目全部找出来；本身访问过滤字段的索引代价预估低。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以问题的关键在于&lt;em&gt;部分&lt;/em&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%9c%9f%e5%ae%9e%e7%9a%84%e6%89%a7%e8%a1%8c%e6%83%85%e5%86%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;explain (analyze,buffers) &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-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; Limit (cost=0.43..1521.93 rows=10 width=990) (actual time=23.311..8122.516 rows=10 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=861100 read=42985 dirtied=7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=6741.003
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan Backward using idx_tablelzl1_column3 on tablelzl1 ri (cost=0.43..157932.45 rows=1038 width=990) (actual time=23.309..8122.505 rows=10 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((column1)::text = &amp;#39;AAAA&amp;#39;::text) AND ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Rows Removed by Filter: 1521796
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=861100 read=42985 dirtied=7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=6741.003
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18) (actual time=0.005..0.005 rows=0 loops=10)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=121 read=28
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=1.476
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning Time: 2.314 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Execution Time: 8122.658 ms&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; Limit (cost=2632.28..3162.78 rows=100 width=990) (actual time=150.101..150.122 rows=14 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=700 read=274
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=146.903
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Result (cost=2632.28..8138.87 rows=1038 width=990) (actual time=150.100..150.119 rows=14 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=700 read=274
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=146.903
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Sort (cost=2632.28..2634.87 rows=1038 width=474) (actual time=150.072..150.073 rows=14 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort Key: ri.column3 DESC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sort Method: quicksort Memory: 30kB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=694 read=274
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=146.903
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using idx_cri_column2 on tablelzl1 ri (cost=0.43..2592.61 rows=1038 width=474) (actual time=0.418..149.973 rows=14 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((column1)::text = &amp;#39;AAAA&amp;#39;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Rows Removed by Filter: 1218
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=691 read=274
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; I/O Timings: read=146.903
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18) (actual time=0.002..0.002 rows=0 loops=14)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit=6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning Time: 0.334 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Execution Time: 150.257 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;limit 10的执行计划，执行8s，内存读shared hit=861100 磁盘读read=42985 ，丢弃了1521796行
limit 100的执行计划执行0.1s shared hit=694 read=274，丢弃了1218行
limit 10的执行计划明显是不正常，&lt;strong&gt;读了太多的数据才找到符合条件的行&lt;/strong&gt;，这是sql执行过慢的原因&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%bb%9f%e8%ae%a1%e4%bf%a1%e6%81%af%e5%88%86%e6%9e%90" 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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres@cnsz381785:7169/(rasesql)phmamp][10-30.15:01:26]M=# select relpages,reltuples::bigint from pg_class where relname=&amp;#39;tablelzl1&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relpages | reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 91172 | 2280874 --count出来差不多&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[phmampopr@cnsz381785:7169/(rasesql)phmamp][10-27.17:08:48]M=&amp;gt; select * from pg_stats where tablename=&amp;#39;tablelzl1&amp;#39; and attname=&amp;#39;column2&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-[ RECORD 1 ]----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;schemaname | public
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tablename | tablelzl1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;attname | column2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;inherited | f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;null_frac | 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;avg_width | 18
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_distinct | -0.11990886
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;most_common_vals | {applyno20231112,DY20190723006650,DY20200102012899,DY20180827000557,DY20190524001304,DY20190529001885,DY20190728002359}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;most_common_freqs | {0.0005,0.00026666667,0.00023333334,0.0002,0.0002,0.0002,0.0002}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;histogram_bounds | {CULZF0000121605605,DSNEW0000126854232,DSNEW0000137652871,DY20160516001057,DY20161104005509,DY20170306002677,DY20170703010428,DY20170928013517,DY20180410007383,DY20180615002936,DY20180
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;correlation | 0.3131596
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;most_common_elems | [null]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;most_common_elem_freqs | [null]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;elem_count_histogram | [null]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个column2 applyno20231112刚好就是排第一的most_common_vals，出现预估概率是0.0005，用预估的行2280874*0.0005=1140，与实际的行数1232差不多&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;[postgres@cnsz381785:7169/(rasesql)phmamp][10-30.15:05:28]M=# select count(*) from tablelzl1 where column2 = &amp;#39;applyno20231112&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; count 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1232&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;说明统计信息是准确的，实际上运行&lt;code&gt;analze&lt;/code&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%95%b0%e6%8d%ae%e5%88%86%e5%b8%83%e4%b8%8d%e5%9d%87%e7%9a%84%e8%ae%a1%e7%ae%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;用当前统计信息计算出来的符合条件的行有1140个，那么预计从排序字段的索引上找到第一条数据平均要扫描2280874/1140=2000个索引行。如果找10条便是20000个索引行，100条便是200000个索引行。&lt;/p&gt;
&lt;p&gt;把sort禁用，让limit 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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; enable_sort&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;/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;--limit 100的执行计划
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Limit (cost=0.43..15222.69 rows=100 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan Backward using idx_tablelzl1_column3 on tablelzl1 ri (cost=0.43..158007.45 rows=1038 width=990)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((column1)::text = &amp;#39;AAAA&amp;#39;::text) AND ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SubPlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Index Scan using uk_tablelzl2_ii on tablelzl2 cl (cost=0.27..5.29 rows=1 width=18)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Index Cond: (((item_no)::text = &amp;#39;manualSign&amp;#39;::text) AND ((item_name)::text = (ri.manual_sign)::text))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;limit 10改成limit 100后的执行计划，代价从1522.66升到了15222.69，基本上只是简单的*10。limit 100的代价15222.69大于了走过滤字段索引的执行计划cost 3162.78，所以limit 10和limit 100执行计划不同，选择了不同的索引。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以上的估算都是以数据零散的放在排序列的索引上 为前提的，实际情况有可能数据在最后一条（反向扫描索引），很快就能找到；也有可能数据全部在索引叶节点前面的几个pages，此时几乎是扫描全部索引并回表，代价便非常高。&lt;/strong&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; -&amp;gt; Index Scan Backward using idx_tablelzl1_column3 on tablelzl1 ri (cost=0.43..157932.45 rows=1038 width=990) (actual time=23.309..8122.505 rows=10 loops=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((column1)::text = &amp;#39;AAAA&amp;#39;::text) AND ((column2)::text = &amp;#39;applyno20231112&amp;#39;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Rows Removed by Filter: 1521796&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;实际上差不多扫描了1521796行才找到这10条数据，本来预估的是20000，整整相差了76倍！&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%a7%a6%e5%8f%91%e5%9c%ba%e6%99%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;必须有where +order by+limit语句&lt;/li&gt;
&lt;li&gt;排序字段和过滤字段都必须有索引&lt;/li&gt;
&lt;li&gt;一般limit不会特别大&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="#%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;改写sql语句：添加表达式，不让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;
&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:#66d9ef"&gt;select&lt;/span&gt; cl.ITEM_DESC &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tablelzl2 cl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; cl.ITEM_NAME &lt;span style="color:#f92672"&gt;=&lt;/span&gt; RI.MANUAL_SIGN &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; cl.ITEM_NO&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;manualSign&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;manualSign&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablelzl1 RI
&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; RI.column1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;AAAA&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;AND&lt;/span&gt; RI.column2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;applyno20231112&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;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RI.column3 &lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &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;10&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;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%e6%98%af%e6%80%8e%e4%b9%88%e5%81%9a%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;执行计划cost的预估差异
 &lt;div id="执行计划cost的预估差异" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%a7%e8%a1%8c%e8%ae%a1%e5%88%92cost%e7%9a%84%e9%a2%84%e4%bc%b0%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;从上面的执行计划分析，pg的执行计划cost看起来不太适应，上层的cost小于内层的cost，不像oracle这样阶梯式的累加计算
这里做一个oracle和pg的实验，一张表仅存储colname=&amp;lsquo;x&amp;rsquo;的数据，看下pg和oracle的对cost计算的区别：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;[postgres@cnsz381785:7169/(rasesql)dbmgr][10-31.14:32:19]M=# explain select * from testlzl where col1=&amp;#39;x&amp;#39; limit 1;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Limit (cost=0.00..0.02 rows=1 width=2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Seq Scan on testlzl (cost=0.00..17747.20 rows=1048576 width=2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((col1)::text = &amp;#39;x&amp;#39;::text)&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;[postgres@cnsz381785:7169/(rasesql)dbmgr][10-31.14:32:30]M=# explain select * from testlzl where col1=&amp;#39;xx&amp;#39; limit 1;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Limit (cost=0.00..17747.20 rows=1 width=2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Seq Scan on testlzl (cost=0.00..17747.20 rows=1 width=2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((col1)::text = &amp;#39;xx&amp;#39;::text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;col1=&amp;lsquo;x&amp;rsquo;立马就能找到，limit的算法没有推入到全表扫描的成本中，total cost是17747.20，跟扫描完表的成本是一样的。limit的成本cost虽然没有下推到内层的cost做计算，但是rows计算了！&lt;/p&gt;
&lt;p&gt;来看下oracle是执行计划是怎么做的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;SYS@t8icss1&amp;gt; select * from dbmgr.testlzl where a=&amp;#39;x&amp;#39; and rownum&amp;lt;=1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1 row selected.
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Execution Plan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plan hash value: 2045386539
&lt;/span&gt;&lt;/span&gt;&lt;span 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;| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 1 | COUNT STOPKEY | | | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 2 | TABLE ACCESS FULL| TESTLZL | 1 | 2 | 2 (0)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Predicate Information (identified by operation 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; 1 - filter(ROWNUM&amp;lt;=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2 - filter(&amp;#34;A&amp;#34;=&amp;#39;x&amp;#39;)&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SYS@t8icss1&amp;gt; select * from dbmgr.testlzl where a=&amp;#39;xx&amp;#39; and rownum&amp;lt;=1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;no rows selected
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Execution Plan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plan hash value: 2045386539
&lt;/span&gt;&lt;/span&gt;&lt;span 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;| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 0 | SELECT STATEMENT | | 1 | 2 | 302 (2)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 1 | COUNT STOPKEY | | | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 2 | TABLE ACCESS FULL| TESTLZL | 1 | 2 | 302 (2)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Predicate Information (identified by operation 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; 1 - filter(ROWNUM&amp;lt;=1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2 - filter(&amp;#34;A&amp;#34;=&amp;#39;xx&amp;#39;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;对于oracle的计划，a=&amp;lsquo;x&amp;rsquo;的数据可以立即找到的话，STOPKEY的代价算进了内层的cost中，cost只有2，实际上扫描全表的代价比较高302。&lt;/p&gt;
&lt;p&gt;这一点是oracle与pg关于cost计算的一个重要区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;oracle的外层cost必然&amp;gt;=内层cost；pg则不一定&lt;/li&gt;
&lt;li&gt;oracle的内层cost计算包含了外层的算子（比如stopkey）；但是pg不会包含，直接给子路径的全部成本&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%e6%95%b0%e6%8d%ae%e5%88%86%e5%b8%83%e4%b8%8d%e5%9d%87%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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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(a char(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,b char(&lt;span style="color:#ae81ff"&gt;100&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:#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:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;100000&lt;/span&gt; loop
&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;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;test&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; loop;
&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:#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;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;aaaa&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;aaaa&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:#66d9ef"&gt;into&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;zzzz&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;zzzz&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 style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl(a);
&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_b &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl(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:#66d9ef"&gt;EXEC&lt;/span&gt; DBMS_STATS.GATHER_TABLE_STATS(OWNNAME&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;SYS&amp;#39;&lt;/span&gt;,TABNAME&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;TLZL&amp;#39;&lt;/span&gt;,estimate_percent &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, degree&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,METHOD_OPT&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;FOR ALL COLUMNS SIZE AUTO&amp;#39;&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;cascade&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&amp;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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; &lt;span style="color:#75715e"&gt;/*+ index(tlzl idx_a)*/&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;aaaa&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; a) &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; rownum&lt;span style="color:#f92672"&gt;&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 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; &lt;span style="color:#75715e"&gt;/*+ index(tlzl idx_a)*/&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tlzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;zzzz&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; a) &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; rownum&lt;span style="color:#f92672"&gt;&amp;lt;=&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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;SYS@t8icss1&amp;gt; select * from (select /*+ index(tlzl idx_a)*/* from tlzl where b=&amp;#39;aaaa&amp;#39; order by a) where rownum&amp;lt;=1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Execution Plan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plan hash value: 3674066029
&lt;/span&gt;&lt;/span&gt;&lt;span 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;| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 0 | SELECT STATEMENT | | 1 | 204 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 1 | COUNT STOPKEY | | | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 2 | VIEW | | 1 | 204 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 3 | TABLE ACCESS BY INDEX ROWID| TLZL | 1 | 202 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 4 | INDEX FULL SCAN | IDX_A | 98830 | | 779 (1)| 00:00: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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;SYS@t8icss1&amp;gt; select * from (select /*+ index(tlzl idx_a)*/* from tlzl where b=&amp;#39;zzzz&amp;#39; order by a) where rownum&amp;lt;=1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Execution Plan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plan hash value: 3674066029
&lt;/span&gt;&lt;/span&gt;&lt;span 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;| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---------------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 0 | SELECT STATEMENT | | 1 | 204 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 1 | COUNT STOPKEY | | | | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 2 | VIEW | | 1 | 204 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;|* 3 | TABLE ACCESS BY INDEX ROWID| TLZL | 1 | 202 | 2210 (1)| 00:00:01 |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;| 4 | INDEX FULL SCAN | IDX_A | 98830 | | 779 (1)| 00:00: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;oracle的优化器也是一样的，优化器并不知道数据到底放在索引的哪个地方，没有办法，放在索引的第一条和最后一条都是估算的同一代价。
不过oracle有很多方法可以解决这个问题，如extended statistic、Automatic Column Group Detection、固化执行计划等。&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="http://www.postgres.cn/v2/news/viewone/1/717" target="_blank" rel="noreferrer"&gt;http://www.postgres.cn/v2/news/viewone/1/717&lt;/a&gt;
&lt;a href="https://oracle-base.com/articles/12c/automatic-column-group-detection-extended-statistics-12cr1" target="_blank" rel="noreferrer"&gt;https://oracle-base.com/articles/12c/automatic-column-group-detection-extended-statistics-12cr1&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>pg truncate浅析</title><link>https://lastdba.com/2024/08/12/pg-truncate%E6%B5%85%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/pg-truncate%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%91%bd%e4%bb%a4%e9%80%89%e9%a1%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;TRUNCATE&lt;/span&gt; [ &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; ] [ &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; ] name [ &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;RESTART&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONTINUE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; ] [ &lt;span style="color:#66d9ef"&gt;CASCADE&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;RESTRICT&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;1&lt;/strong&gt;.&lt;code&gt;ONLY&lt;/code&gt;:只truncate指定的表。当表有继承子表或有子分区时，默认会一起truncate;only可只truncate继承父表。分区父表不能指定only&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%91%bd%e4%bb%a4%e9%80%89%e9%a1%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;TRUNCATE&lt;/span&gt; [ &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; ] [ &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; ] name [ &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;RESTART&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONTINUE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&lt;/span&gt; ] [ &lt;span style="color:#66d9ef"&gt;CASCADE&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;RESTRICT&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;1&lt;/strong&gt;.&lt;code&gt;ONLY&lt;/code&gt;:只truncate指定的表。当表有继承子表或有子分区时，默认会一起truncate;only可只truncate继承父表。分区父表不能指定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;--不能truncate only分区父表
&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;only&lt;/span&gt; parttable;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;42809&lt;/span&gt;: cannot &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;only&lt;/span&gt; a partitioned &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;HINT: &lt;span style="color:#66d9ef"&gt;Do&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; specify the &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; keyword, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; use &lt;span style="color:#66d9ef"&gt;TRUNCATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ONLY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; the partitions directly.
&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;: ExecuteTruncate, tablecmds.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1655&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;--truncate only继承父表，只清理父表
&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;only&lt;/span&gt; parenttable;
&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 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; parenttable &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; childtable &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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 style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; parenttable;
&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 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; parenttable &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;(&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;&lt;strong&gt;2&lt;/strong&gt;.&lt;code&gt;RESTART IDENTITY&lt;/code&gt; &lt;code&gt;CONTINUE IDENTITY&lt;/code&gt;:&lt;strong&gt;列上&lt;/strong&gt;的序列是否要重置，默认CONTINUE。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--bigserial 默认会创建列上的序列
&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; tableserial (a bigserial &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,b 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;
&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; tableserial;
&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.tableserial&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; a &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;tableserial_a_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; b &lt;span style="color:#f92672"&gt;|&lt;/span&gt; name &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; 
&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; tableserial(b) &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; md5(random()::text) &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&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;1000&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--seq当前值为1000
&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; currval(&lt;span style="color:#e6db74"&gt;&amp;#39;tableserial_a_seq&amp;#39;&lt;/span&gt;::regclass);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currval 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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 style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tableserial;
&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 style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; currval(&lt;span style="color:#e6db74"&gt;&amp;#39;tableserial_a_seq&amp;#39;&lt;/span&gt;::regclass) cur,nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;tableserial_a_seq&amp;#39;&lt;/span&gt;::regclass);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cur &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--显示指定RESTART IDENTITY，重置序列
&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tableserial &lt;span style="color:#66d9ef"&gt;RESTART&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&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 style="color:#75715e"&gt;--注意seq在nextval时重置了
&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; currval(&lt;span style="color:#e6db74"&gt;&amp;#39;tableserial_a_seq&amp;#39;&lt;/span&gt;::regclass) cur,nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;tableserial_a_seq&amp;#39;&lt;/span&gt;::regclass);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cur &lt;span style="color:#f92672"&gt;|&lt;/span&gt; nextval 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;1001&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;3&lt;/strong&gt;.&lt;code&gt;CASCADE&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;--创建主表和外键表和数据
&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; pri_tab(id bigint &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,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;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; pri_tab &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:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;),(&lt;span style="color:#ae81ff"&gt;3&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;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:#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; frn_tab(id bigint,&lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt; (id) &lt;span style="color:#66d9ef"&gt;REFERENCES&lt;/span&gt; pri_tab(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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; frn_tab &lt;span style="color:#66d9ef"&gt;values&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;&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;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:#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; pri_tab;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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:#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 style="color:#ae81ff"&gt;3&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:#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;&lt;span style="color:#75715e"&gt;--外键表frn_tab依赖主表pri_tab的数据
&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; frn_tab;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;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:#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;--有主表外键reference时，外键表必须跟cascade，否则无法清理
&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; pri_tab ;
&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;truncate&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; referenced &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;foreign&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: &lt;span style="color:#66d9ef"&gt;Table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;frn_tab&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;references&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pri_tab&amp;#34;&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;Truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;frn_tab&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;at&lt;/span&gt; the same time, &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; use &lt;span style="color:#66d9ef"&gt;TRUNCATE&lt;/span&gt; ... &lt;span style="color:#66d9ef"&gt;CASCADE&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;: heap_truncate_check_FKs, heap.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3427&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; pri_tab &lt;span style="color:#66d9ef"&gt;cascade&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;: &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; cascades &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;frn_tab&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;: ExecuteTruncateGuts, tablecmds.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1725&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 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; pri_tab;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;span style="display: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; frn_tab;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;由于外键表依赖主表的数据，不能直接truncate主表，必须加cascade，此时外键表也跟随主表一起清空&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt;.&lt;code&gt;RESTRICT&lt;/code&gt;
是否清理foreign key表。没什么用，default选项，加不加都是这样。清理附带的外键表应加CASCADE。&lt;/p&gt;

&lt;h2 class="relative group"&gt;MVCC/transaction
 &lt;div id="mvcctransaction" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mvcctransaction" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg官方文档有这么一段化&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;TRUNCATE&lt;/code&gt; is not MVCC-safe. After truncation, the table will appear empty to concurrent transactions, if they are using a snapshot taken before the truncation occurred.
&lt;code&gt;TRUNCATE&lt;/code&gt; is transaction-safe with respect to the data in the tables: the truncation will be safely rolled back if the surrounding transaction does not commit.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;transaction-safe意思是可以放在事务块里，可以回退
回滚truncate：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;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;truncate&lt;/span&gt; t1;
&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 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;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; t1;
&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;100&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 MVCC-safe意思是一个会话在truncate前打了一个快照，快照期间如果发生truncate，这个快照是可以读到truncate清理后的结果的。这不符合MVCC。
不过这个问题不算太大，在会话场景下，因为truncate是8级锁，快照没有结束的话最低在表上有一个读共享锁，所以truncate不会执行。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This will only be an issue for a transaction that did not access the table in question before the DDL command started —any transaction that has done so would hold at least an &lt;code&gt;ACCESS SHARE&lt;/code&gt; table lock, which would block the DDL command until that transaction completes&lt;/p&gt;
&lt;/blockquote&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%8a%9f%e8%83%bd%e6%9b%b4%e6%96%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c1c4036557be.png" alt="在这里插入图片描述" /&gt;
truncate更新功能不多，只需要注意14的时候支持truncate foreign tables即可。truncate foreign tables前提是fdw得支持TRUNCATE API&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Also it extends postgres_fdw so that it can issue TRUNCATE command to foreign servers, by adding new routine for that TRUNCATE API.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;pg truncate和其他库的功能差异
 &lt;div id="pg-truncate和其他库的功能差异" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-truncate%e5%92%8c%e5%85%b6%e4%bb%96%e5%ba%93%e7%9a%84%e5%8a%9f%e8%83%bd%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


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



&lt;img src="https://lastdba.com/img/csdn/b7ebb636b6b2.png" alt="在这里插入图片描述" /&gt;
truncate很快、8级锁等特性已经是人尽皆知的事情了，相对于其他数据库，pg还可以：&lt;strong&gt;选择是否重置序列&lt;/strong&gt;（&lt;code&gt;RESTART IDENTITY&lt;/code&gt; &lt;code&gt;CONTINUE IDENTITY&lt;/code&gt;）、&lt;strong&gt;回滚&lt;/strong&gt;、&lt;strong&gt;简单的授权&lt;/strong&gt;。&lt;/p&gt;

&lt;h2 class="relative group"&gt;truncate做了什么
 &lt;div id="truncate做了什么" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e5%81%9a%e4%ba%86%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; lzl(a int);
&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; lzl_idx &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;create&lt;/span&gt; sequence lzl_seq &lt;span style="color:#66d9ef"&gt;start&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl_seq&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;--select pg_relation_filepath(&amp;#39;lzl&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;--db路径
&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; oid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_database &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; datname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;lzldb&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;418679&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--刚创建时候各个rel的oid=relfilenode
&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; relname,oid,relfilenode,relkind &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:#66d9ef"&gt;like&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------+-------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S
&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;&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&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;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 style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,oid,relfilenode,relkind &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:#66d9ef"&gt;like&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------+-------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428370&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428371&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--truncate后，表和索引重建了，sequence却没有
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span 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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;RESTART&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&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 style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,oid,relfilenode,relkind &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:#66d9ef"&gt;like&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------+-------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428372&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428373&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--显示restart，sequence还是没有重建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span 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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; sequence lzl_seq &lt;span style="color:#66d9ef"&gt;restart&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; SEQUENCE
&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;select&lt;/span&gt; relname,oid,relfilenode,relkind &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:#66d9ef"&gt;like&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------+-------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428372&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428373&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428374&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--显示restart sequence是会重建sequence的&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;truncate ···RESTART IDENTITY&lt;/code&gt;没有重建我们sequence，&lt;code&gt;alter sequence lzl_seq restart&lt;/code&gt;重建了sequence。应该是&lt;code&gt;RESTART IDENTITY&lt;/code&gt;没有理解对。在看下官方文档对&lt;code&gt;RESTART IDENTITY&lt;/code&gt;的解释&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Automatically restart sequences owned by columns of the truncated table(s).&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;sequence必须&lt;code&gt;owned by&lt;/code&gt;表上的列，注意不是&lt;code&gt;owner to&lt;/code&gt;。虽然&lt;code&gt;\d&lt;/code&gt;可以看到表上的sequence，但是它可能不属于表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; lzl;
&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.lzl&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; 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; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;lzl_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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;用&lt;code&gt;owned by&lt;/code&gt;修改sequence的所属表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; SEQUENCE lzl_seq OWNED &lt;span style="color:#66d9ef"&gt;BY&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;ALTER&lt;/span&gt; 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:#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; s.relname &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; seq, n.nspname &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; sch, t.relname &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; tab, a.attname &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; col 
&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_class s 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_depend d &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; d.objid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;s.oid &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; d.classid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;pg_class&amp;#39;&lt;/span&gt;::regclass &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; d.refclassid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;pg_class&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:#66d9ef"&gt;JOIN&lt;/span&gt; pg_class t &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; t.oid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.refobjid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_namespace n &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; n.oid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t.relnamespace 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; pg_attribute a &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; a.attrelid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t.oid &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; a.attnum&lt;span style="color:#f92672"&gt;=&lt;/span&gt;d.refobjsubid 
&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; s.relkind&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; d.deptype&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sch &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tab &lt;span style="color:#f92672"&gt;|&lt;/span&gt; col 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------------------+--------+-------------+-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableserial_a_seq &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; tableserial &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; lzl_seq &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; lzl &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&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;truncate&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;RESTART&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IDENTITY&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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; relname,oid,relfilenode,relkind &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:#66d9ef"&gt;like&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; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relfilenode &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relkind 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+--------+-------------+---------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428363&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428375&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_idx &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428366&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428376&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_seq &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428367&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;428377&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;sequence owned by表上的列时，truncate显示带RESTART IDENTITY就会restart这个sequence，也就重建了sequence。&lt;strong&gt;默认以serial/bigserial方式创建的序列是被表拥有的，随表drop而删除；那些不被表拥有的序列，drop不会删除&lt;/strong&gt;。
truncate重建特性汇总：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接truncate table会重建表和索引&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;truncate table+RESTART IDENTITY，会重建（也就是retart）属于这个表的sequence。只要不属于这个表的sequence，哪怕列上关联了seq的默认值，也不会重建这个seq&lt;/strong&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="#%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;truncate也是utility命令，很快就可以找到入口函数
&lt;code&gt;src/backend/commands/tablecmds.c&lt;/code&gt;中的&lt;code&gt;ExecuteTruncate&lt;/code&gt;为入口函数，注释其实已经说明truncate要获得exclusive lock，并检查权限和relation是否ok，递归检查所有需要truncate的表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ExecuteTruncate&lt;/span&gt;(TruncateStmt &lt;span style="color:#f92672"&gt;*&lt;/span&gt;stmt)
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#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;* Open, exclusive-lock, and check all the explicitly-specified relations
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, stmt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relations)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;LOCKMODE lockmode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AccessExclusiveLock; &lt;span style="color:#75715e"&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;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;table_open&lt;/span&gt;(myrelid, NoLock); &lt;span 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:#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;ExecuteTruncate&lt;/span&gt;(TruncateStmt &lt;span style="color:#f92672"&gt;*&lt;/span&gt;stmt)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;foreach&lt;/span&gt;(cell, stmt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relations)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;		LOCKMODE	lockmode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AccessExclusiveLock; &lt;span style="color:#75715e"&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;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* open the relation, we already hold a lock on it */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		rel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;table_open&lt;/span&gt;(myrelid, NoLock); &lt;span 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;truncate_check_activity&lt;/span&gt;(rel); &lt;span 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; (recurse) &lt;span 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;			children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;find_all_inheritors&lt;/span&gt;(myrelid, lockmode, NULL); &lt;span 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;foreach&lt;/span&gt;(child, children)
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#a6e22e"&gt;truncate_check_rel&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;RelationGetRelid&lt;/span&gt;(rel), rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;truncate_check_activity&lt;/span&gt;(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;				rels &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lappend&lt;/span&gt;(rels, rel); &lt;span style="color:#75715e"&gt;//加入到待truncate的rel队列中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				relids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lappend_oid&lt;/span&gt;(relids, childrelid);
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#75715e"&gt;//发现truncate only分区父表，直接报错
&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; (rel&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_TABLE)
&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;(ERROR,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					(&lt;span style="color:#a6e22e"&gt;errcode&lt;/span&gt;(ERRCODE_WRONG_OBJECT_TYPE),
&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;cannot truncate only a partitioned table&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;errhint&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#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;ExecuteTruncateGuts&lt;/span&gt;(rels, relids, relids_logged,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						stmt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;behavior, stmt&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;restart_seqs);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* And close the rels */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, rels)
&lt;/span&gt;&lt;/span&gt;&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	rel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Relation) &lt;span style="color:#a6e22e"&gt;lfirst&lt;/span&gt;(cell);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;(rel, NoLock);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;ExecuteTruncateGuts&lt;/code&gt;函数不仅被truncate命令调用，还被订阅端调用（发布订阅可以同步truncate）。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;ExecuteTruncateGuts&lt;/span&gt;(List &lt;span style="color:#f92672"&gt;*&lt;/span&gt;explicit_rels,
&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;relids,
&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;relids_logged,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					DropBehavior behavior, &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; restart_seqs)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	rels &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list_copy&lt;/span&gt;(explicit_rels);
&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; (behavior &lt;span style="color:#f92672"&gt;==&lt;/span&gt; DROP_CASCADE) &lt;span style="color:#75715e"&gt;//如果指定了cascade选项,提取所有reference的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:#66d9ef"&gt;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;			newrelids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;heap_truncate_find_FKs&lt;/span&gt;(relids); &lt;span style="color:#75715e"&gt;//找到fk
&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; (newrelids &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NIL)
&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;/* nothing else to add */&lt;/span&gt; &lt;span style="color:#75715e"&gt;//没有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:#a6e22e"&gt;foreach&lt;/span&gt;(cell, newrelids)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;				rel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;table_open&lt;/span&gt;(relid, AccessExclusiveLock); &lt;span style="color:#75715e"&gt;//所有rel获得AccessExclusiveLock
&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;(NOTICE,
&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;truncate cascades to table &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;&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;RelationGetRelationName&lt;/span&gt;(rel))));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;truncate_check_rel&lt;/span&gt;(relid, rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel); &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 style="color:#a6e22e"&gt;truncate_check_perms&lt;/span&gt;(relid, rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel); &lt;span style="color:#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;truncate_check_activity&lt;/span&gt;(rel); &lt;span 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&gt;&lt;/span&gt;&lt;span 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; (restart_seqs) &lt;span style="color:#75715e"&gt;//restart seq的处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;foreach&lt;/span&gt;(cell, rels)
&lt;/span&gt;&lt;/span&gt;&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	rel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (Relation) &lt;span style="color:#a6e22e"&gt;lfirst&lt;/span&gt;(cell);
&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;seqlist &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getOwnedSequences&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;RelationGetRelid&lt;/span&gt;(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;			&lt;span style="color:#75715e"&gt;//只是做sequence的权限检查
&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;pg_class_ownercheck&lt;/span&gt;(seq_relid, &lt;span style="color:#a6e22e"&gt;GetUserId&lt;/span&gt;()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#a6e22e"&gt;aclcheck_error&lt;/span&gt;(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 &lt;span style="color:#a6e22e"&gt;RelationGetRelationName&lt;/span&gt;(seq_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;		}
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#75715e"&gt;//执行所有before truncate触发器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, rels)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ExecBSTruncateTriggers&lt;/span&gt;(estate, resultRelInfo);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		resultRelInfo&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:#75715e"&gt;//正式开始truncate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, rels)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;if&lt;/span&gt; (rel&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_TABLE)
&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:#75715e"&gt;//如果是foreign 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;if&lt;/span&gt; (rel&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_FOREIGN_TABLE)
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#75715e"&gt;//如果是同一事务，因为可能会回退，直接执行heap_truncate_one_rel函数，不创建新的relfilenode
&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; (rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_createSubid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; mySubid &lt;span style="color:#f92672"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_newRelfilenodeSubid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; mySubid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Immediate, non-rollbackable truncation is OK */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;heap_truncate_one_rel&lt;/span&gt;(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;		&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//设置NewRelfilenode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;RelationSetNewRelfilenode&lt;/span&gt;(rel, rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relpersistence);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			heap_relid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RelationGetRelid&lt;/span&gt;(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;			 &lt;span style="color:#75715e"&gt;//toast同理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			toast_relid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;reltoastrelid;
&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;OidIsValid&lt;/span&gt;(toast_relid))
&lt;/span&gt;&lt;/span&gt;&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	toastrel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;relation_open&lt;/span&gt;(toast_relid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;													 AccessExclusiveLock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;RelationSetNewRelfilenode&lt;/span&gt;(toastrel,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 toastrel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rd_rel&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;relpersistence);
&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;(toastrel, NoLock);
&lt;/span&gt;&lt;/span&gt;&lt;span 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:#a6e22e"&gt;reindex_relation&lt;/span&gt;(heap_relid, REINDEX_REL_PROCESS_TOAST,
&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;reindex_params);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;pgstat_count_truncate&lt;/span&gt;(rel); &lt;span style="color:#75715e"&gt;//更新pgstat的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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//重置sequence 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, seq_relids)
&lt;/span&gt;&lt;/span&gt;&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			seq_relid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lfirst_oid&lt;/span&gt;(cell);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ResetSequence&lt;/span&gt;(seq_relid);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//写wal
&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;list_length&lt;/span&gt;(relids_logged) &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;	...
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//触发AFTER TRUNCATE triggers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	resultRelInfo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; resultRelInfos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;foreach&lt;/span&gt;(cell, rels)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;ExecASTruncateTriggers&lt;/span&gt;(estate, resultRelInfo);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		resultRelInfo&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ExecuteTruncateGuts&lt;/code&gt;函数根据truncate选项进行处理，处理过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;根据cascade选项找到所有reference的外键表&lt;/li&gt;
&lt;li&gt;触发before truncate触发器&lt;/li&gt;
&lt;li&gt;执行truncate&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果是同一事务，不立即生成&lt;code&gt;NewRelfilenode&lt;/code&gt;，直接调用函数&lt;code&gt;heap_truncate_one_rel&lt;/code&gt;进行truncate&lt;/li&gt;
&lt;li&gt;如果不是同一事务，调用&lt;code&gt;RelationSetNewRelfilenode&lt;/code&gt;新建&lt;code&gt;NewRelfilenode&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;code&gt;reindex_relation&lt;/code&gt;函数重建索引&lt;/li&gt;
&lt;li&gt;根据restart identity重置sequence&lt;/li&gt;
&lt;li&gt;写wal日志&lt;/li&gt;
&lt;li&gt;触发after truncate触发器&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;后面大概追了下函数，套娃比较多
&lt;code&gt;RelationSetNewRelfilenode&lt;/code&gt;
&lt;code&gt;table_relation_set_new_filenode&lt;/code&gt;
&lt;code&gt;relation_set_new_filenode&lt;/code&gt;在这里插入代码片
&lt;code&gt;heapam_relation_set_new_filenode&lt;/code&gt;
&lt;code&gt;RelationCreateStorage&lt;/code&gt;
然后到&lt;code&gt;src/backend/storage/smgr/smgr.c&lt;/code&gt;中的&lt;code&gt;smgrcreate&lt;/code&gt;和&lt;code&gt;smgr_create&lt;/code&gt;。后面就没看太懂了（一到函数指针就有点追不到的感觉，先这样吧~）···
对于&lt;code&gt;smgr.c&lt;/code&gt;有这样的注释：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;public interface routines to storage manager switch
All file system operations in POSTGRES dispatch through these routines.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;任何文件系统操作都会经过smgr（storage manager）；到这里就是文件系统操作了。&lt;/p&gt;

&lt;h2 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;/h2&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/15/sql-truncate.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/15/sql-truncate.html&lt;/a&gt;
&lt;a href="https://www.postgresql.org/docs/current/mvcc-caveats.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/mvcc-caveats.html&lt;/a&gt;
&lt;a href="https://pgpedia.info/t/truncate.html" target="_blank" rel="noreferrer"&gt;https://pgpedia.info/t/truncate.html&lt;/a&gt;
&lt;a href="https://www.orafaq.com/wiki/SQL_FAQ" target="_blank" rel="noreferrer"&gt;https://www.orafaq.com/wiki/SQL_FAQ&lt;/a&gt;
&lt;a href="https://learnsql.com/blog/difference-between-truncate-delete-and-drop-table-in-sql/" target="_blank" rel="noreferrer"&gt;https://learnsql.com/blog/difference-between-truncate-delete-and-drop-table-in-sql/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>pg报错attempted to delete invisible tuple</title><link>https://lastdba.com/2024/08/12/pg%E6%8A%A5%E9%94%99attempted-to-delete-invisible-tuple/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/pg%E6%8A%A5%E9%94%99attempted-to-delete-invisible-tuple/</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%e6%8f%8f%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;postgresql数据库执行delete报错：&lt;code&gt;attempted to delete invisible tuple&lt;/code&gt;，执行同样条件的select不报错&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%e6%8f%8f%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;postgresql数据库执行delete报错：&lt;code&gt;attempted to delete invisible tuple&lt;/code&gt;，执行同样条件的select不报错&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;delete&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzltab1;
&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; lzltab1;&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;M&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; lzltab1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: &lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;: attempted &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt; invisible tuple
&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;: heap_delete, heapam.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2500&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;511&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;050&lt;/span&gt; ms&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;M&lt;span style="color:#f92672"&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; lzltab1;
&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;231187&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;delete找到了不可见的元组，select却是正常的 。
当时觉得很奇怪。pg的可见性通过元组的xmin,xmax,cid和快照的xmin，xmax，xip_list判断的，虽然delete元组的事务状态和时间会对可见性产生影响，但是表数据如果稳定（当前没有任何dml操作的话），随后的任何快照进去拍摄，都应该是一个稳定的可见集，它并不存在当前事务可见性判断，dml事务元组可见性判断也应该一致。也就是说这种场景下，select快照和delete快照不应该有这种差异。&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="#%e6%89%be%e5%88%b0%e6%ba%90%e7%a0%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;注意报错信息&lt;code&gt;heapam.c:2500&lt;/code&gt;
找到源码位置&lt;code&gt;src/backend/access/heap/heapam.c&lt;/code&gt;
2500的行是空的，附近的代码如下&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;	 * Before locking the buffer, pin the visibility map page if it appears 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;	 * be necessary. Since we haven&amp;#39;t got the lock yet, someone else might be
&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 the middle of changing this, so we&amp;#39;ll need to recheck after we have
&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 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;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;PageIsAllVisible&lt;/span&gt;(page))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;visibilitymap_pin&lt;/span&gt;(relation, block, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;vmbuffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;LockBuffer&lt;/span&gt;(buffer, BUFFER_LOCK_EXCLUSIVE);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;从源码看，它在尝试获得vm上的锁，看来问题跟vm文件相关。&lt;/p&gt;

&lt;h3 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%e6%96%87%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是vm文件？&lt;/strong&gt;
vm文件是为了减少vacuum扫描page时间的，如果一个page不需要vacuum那么它应该可以被vacuum跳过，这样可以大大减少vacuum寻找需要清理的page的时间，这是vm文件最初的目的。（有时候也会被index-only scan使用，不过我们这里不会涉及，我们用的是全表扫描）
vm文件包含两个信息：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;page中的元组是不是都是可见的。说明page中没有需要被vacuum的死元组&lt;/li&gt;
&lt;li&gt;page中的元组是不是都是冻结的。说明vacuum freeze不需要访问这个page&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/1604296b876a.png" alt="Fig. 6.2. How the VM is used." /&gt;&lt;/p&gt;
&lt;p&gt;vm会帮助vacuum寻找死元组，减少扫描的页的数量。比如上面这个图（interdb yyds！），第一个页面1st不包含死元组，那么vacuum就可以跳过这个页面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;找到vm文件&lt;/strong&gt;
每个表都有Visibility Map (VM)（索引没有vm文件），单独存放在表文件的旁边，如果一个表的filenode为&lt;code&gt;12345&lt;/code&gt;，那么vm文件应该是&lt;code&gt;12345_vm&lt;/code&gt;
首先cd到data目录&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;# show data_directory;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_directory 
&lt;/span&gt;&lt;/span&gt;&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/pg6666/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过database oid，表的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;&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; oid,datname &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_database &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; datname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;sdp&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; oid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;17075&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sdp
&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; oid,relname &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;lzltab1&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 style="color:#ae81ff"&gt;17362&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzltab1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pg_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&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;17075&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17362&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;找到数据文件和vm&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;$ cd /pg/pg6666/data/base/17075
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ll 17362*
&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;86761472&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; 17:43 &lt;span style="color:#ae81ff"&gt;17362&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;40960&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 17362_fsm
&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;8192&lt;/span&gt; Nov &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2022&lt;/span&gt; 17362_vm&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_visibility插件
 &lt;div id="pg_visibility插件" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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_visibility%e6%8f%92%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg_visibility提供通过检查vm文件输出页级别的可见性信息，而且可以检测vm是否损坏。因为vm存储了“&lt;em&gt;page中的元组是不是都是可见的；page中的元组是不是都是冻结的&lt;/em&gt;”这些信息，pg_visibility可以检查出哪些页是all-frozen的，哪些是all-visible的。
pg_visibility插件使用参考：&lt;a href="https://www.postgresql.org/docs/current/pgvisibility.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/pgvisibility.html&lt;/a&gt;&lt;/p&gt;

&lt;h4 class="relative group"&gt;会用到的pg_visibility中的function
 &lt;div id="会用到的pg_visibility中的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="#%e4%bc%9a%e7%94%a8%e5%88%b0%e7%9a%84pg_visibility%e4%b8%ad%e7%9a%84function" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;pg_visibility_map_summary()&lt;/strong&gt;：显示vm中的all-visible页和all-frozen页
&lt;strong&gt;pg_check_frozen()&lt;/strong&gt;：有元组不是frozen的，但在它所在的页在vm中被标记为了all-frozen，如果该函数有返回，表示vm文件损坏。
&lt;strong&gt;pg_check_visible()&lt;/strong&gt;：有元组不是visible的，但在它所在的页在vm中被标记为了all-visible，如果该函数有返回，表示vm文件损坏。
&lt;strong&gt;pg_truncate_visibility_map()&lt;/strong&gt;：清理vm文件。清理vm后，当表首次执行vacuum时，会扫描表上的所有页并重建vm。&lt;/p&gt;

&lt;h3 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="#%e4%bf%ae%e5%a4%8dvm%e6%96%87%e4%bb%b6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;检查vm是否损坏&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_visibility_map_summary(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_visibility_map_summary 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;472&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;all-visible 472页，all-frozen 0页&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_check_frozen(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_check_frozen 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;span style="display:flex;"&gt;&lt;span&gt;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_check_visible(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_check_visible 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;6839&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;6839&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:#ae81ff"&gt;7296&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;1423&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;pg_check_visible()有结果说明&lt;strong&gt;vm已经损坏了&lt;/strong&gt;
然后用pg_truncate_visibility_map()执行清空vm&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_truncate_visibility_map(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_truncate_visibility_map 
&lt;/span&gt;&lt;/span&gt;&lt;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;从磁盘上也能看出来vm被清空了&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; ll 17362*
&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;86761472&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; 10:39 &lt;span style="color:#ae81ff"&gt;17362&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;40960&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 21:09 17362_fsm
&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;0&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; 18:18 17362_vm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;然后我们验证一下，vacuum表看下是否会生产vm文件，并检验vm文件是否没有损坏&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;vacuum&lt;/span&gt; lzltab1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;VACUUM&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;3692&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;402&lt;/span&gt; ms (&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;692&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;=#&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 style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll &lt;span style="color:#ae81ff"&gt;17362&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;rw&lt;span style="color:#75715e"&gt;------- 1 postgres postgres 86761472 Jun 28 03:37 17362
&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 postgres postgres 40960 Jun 9 21:09 17362_fsm
&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 postgres postgres 8192 Jun 28 10:21 17362_vm&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后vm正常生成&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_check_visible(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_check_visible 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;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;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pg_check_frozen(&lt;span style="color:#e6db74"&gt;&amp;#39;lzltab1&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pg_check_frozen 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;check检查后没有输出，vm文件正常，修复完成。&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:#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; lzltab1;
&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;229766&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;delete执行正常，问题解决&lt;/p&gt;

&lt;h3 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="#%e6%a3%80%e6%9f%a5%e5%85%a8%e5%ba%93%e6%98%af%e5%90%a6%e6%9c%89vm%e6%8d%9f%e5%9d%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;虽然我们解决了一个vm文件损坏的问题，但是仍然需要全库检查是否有其他的vm损坏（前提是安装了extension pg_visibility)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; oid::regclass &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; relname
&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_class
&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; relkind &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;m&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;t&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;EXISTS&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_check_visible(oid))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXISTS&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_check_frozen(oid)));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果返回非空结果，说明有vm损坏了。就像上面的方法，用pg_truncate_visibility_map()清理vm，然后vacuum生成一个vm。
如果是9.6前的版本，因为没有pg_visibility插件，需要停库然后手动删除vm文件，再启动数据库，然后再vacuum生成一个vm。&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="#%e4%b8%ba%e4%bb%80%e4%b9%88vm%e4%bc%9a%e6%8d%9f%e5%9d%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;我们通过一步步分析，检查到是vm文件损坏了，但是vm为什么会损坏呢？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;pg数据库的bug。pg确实有些bug会导致vm损坏（参考wiki Visibility Map Problems），不过这些都是pg9.6.1以前的&lt;/li&gt;
&lt;li&gt;操作系统和硬件问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们版本是pg13的，问题基本只能笼统地归于操作系统或者硬件问题。&lt;/p&gt;

&lt;h2 class="relative group"&gt;为什么select没有问题，delete报错？
 &lt;div id="为什么select没有问题delete报错" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%88select%e6%b2%a1%e6%9c%89%e9%97%ae%e9%a2%98delete%e6%8a%a5%e9%94%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;select全表正常，delete全表报错，看上去就很奇怪。问题的根因是vm文件的损坏。
就像前面说的，vm文件是为了加快vacuum效率的，我们虽然没有做vacuum，而vm文件总要更新的吧？dml每次都会去更新vm（至少要检查），而select不会改变vm状态的。所以本案例中select正常执行，delete在执行到vm的处理时报错。
我们的案例中，delete扫描了vm找到了all-visible的页，但是vm标记错了，这些页上仍然有不可见的元组，这里就对应了开头的报错&lt;code&gt;attempted to delete invisible tuple&lt;/code&gt;。不可见的元组可能已经被delete了，再次跑delete当然会报错，这也违背了事务的可见性规则。
另外，如果是index-only-scan也会用到vm文件，所以也会影响select语句，不过这个案例是全表扫描的，所以select没有问题。&lt;/p&gt;

&lt;h2 class="relative group"&gt;vm损坏导致index-only-scan出现错误的数据结果
 &lt;div id="vm损坏导致index-only-scan出现错误的数据结果" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e6%8d%9f%e5%9d%8f%e5%af%bc%e8%87%b4index-only-scan%e5%87%ba%e7%8e%b0%e9%94%99%e8%af%af%e7%9a%84%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;前面在介绍vm的时候提到处理vacuum外，index-only-scan也会用到vm文件，虽然我们这个案例没有涉及index-only-scan，但本着研究透彻的原则，把问题搞清楚。&lt;/p&gt;

&lt;h3 class="relative group"&gt;什么是index-only-scan
 &lt;div id="什么是index-only-scan" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%afindex-only-scan" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;index-only-scan顾名思义就是仅索引扫描。在访问数据的时候不需要访问表，而只访问索引结构就能得到想要的结果。几乎所有的关系型数据库都有仅索引扫描，因为B+树索引结构保存了键值，如果查询只查了键值，那么仅索引扫描就是可能的。
但是，postgresql因为其事务实现跟其他数据库（Oracle、mysql）有很大的不同，它的仅索引扫描index-only-scan有一些特殊性。
postgresql通过元组头部的xmin、xmax等信息，校验元组和事务的可见性，而索引上没有这些信息，所以就导致pg的仅索引扫描必须访问数据块来检查可见性。这个时候vm的作用就体现了出来，因为vm文件中保存了all-visible，all-frozen的信息，这些被标记的页其实不需要校验元组可见性，因为他们已经被vm标记为可见了。



&lt;img src="https://lastdba.com/img/csdn/63ed5a39f52d.png" alt="Fig. 7.7. How Index-Only Scans performs" /&gt;
再来一个interdb的图（interdb yyds！）。当一个sql查询在访问key是18和19两个元组时，key=18元组所在的页已经被vm标记为all-visible了，所以访问key=18的元组只需要访问索引页和vm文件；而key=19的元组所在的页没有被标记为all-visible，仅索引扫描还是要访问所在数据页获取元组可见信息。&lt;/p&gt;

&lt;h3 class="relative group"&gt;index-only-scan查询出错误的结果
 &lt;div id="index-only-scan查询出错误的结果" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#index-only-scan%e6%9f%a5%e8%af%a2%e5%87%ba%e9%94%99%e8%af%af%e7%9a%84%e7%bb%93%e6%9e%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为index-only-scan要访问vm，而vm损坏而保存了错误的信息，比如页中的元组本来不是所有都可见的（比如几个元组被delete了），但是页还是在vm中被标记为all-visible，导致index-only-scan没有进数据页检测元组可见性，直接返回了索引页上的本来是不可见的键值。
可以设置&lt;code&gt;enable_indexonlyscan=off&lt;/code&gt;来关闭index-only-scan特性，保证数据的正确性；当然也可以像上面那样去修复vm文件，也许是更好的选择。&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;p&gt;虽然刚开始有些曲折，一看报错以为是事务可见性规则出现了问题，这个有问题的话问题就有点大了，但是实际上要简单的多。
我们从报错&lt;code&gt;attempted to delete invisible tuple&lt;/code&gt;分析到源码，并定位到了是vm问题，再通过pg_visibility插件检测出vm corrupt并修复了vm文件，从而解决了delete报错，最后扩展了一下index-only-scan和vm。
总结一下文章的知识点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg_visibility插件可以读取、检测、清理vm文件&lt;/li&gt;
&lt;li&gt;如果没有vm信息的话，vacuum会生成新的vm&lt;/li&gt;
&lt;li&gt;dml会读取/更新vm文件，select不会（非index-only-scan）&lt;/li&gt;
&lt;li&gt;vm文件是为了提升vacuum的效率，有时候也会提升index-only-scan的效率&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attempted to delete invisible tuple&lt;/code&gt;报错应该检查vm文件是否损坏&lt;/li&gt;
&lt;li&gt;vm文件损坏会造成dml失败，也会造成index-only-scan查询出错误的结果&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.postgresql.org/docs/13/pgvisibility.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/13/pgvisibility.html&lt;/a&gt;
&lt;a href="https://wiki.postgresql.org/wiki/Visibility_Map_Problems" target="_blank" rel="noreferrer"&gt;https://wiki.postgresql.org/wiki/Visibility_Map_Problems&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.interdb.jp/pg/pgsql07.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql07.html&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>pg逻辑复制的一些特性</title><link>https://lastdba.com/2024/08/12/pg%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E7%9A%84%E4%B8%80%E4%BA%9B%E7%89%B9%E6%80%A7/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/pg%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E7%9A%84%E4%B8%80%E4%BA%9B%E7%89%B9%E6%80%A7/</guid><description>&lt;p&gt;之前已经写过一篇比较详细的&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170082845616800211565759%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170082845616800211565759&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-129291207-null-null.nonecase&amp;amp;utm_term=%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;关于逻辑复制的文章&lt;/a&gt;了，这里不会再重复描述一些基础知识。不过难免有些知识点有遗漏，最近发一些有意思的逻辑复制特性。&lt;/p&gt;

&lt;h2 class="relative group"&gt;replica identity与old/new值
 &lt;div id="replica-identity与oldnew值" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e4%b8%8eoldnew%e5%80%bc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;replica identity是用来在逻辑复制期间标识一行数据的。
上面这句话当然没有问题，但是没有解释old和new数据的变化。&lt;/p&gt;</description><content:encoded>&lt;p&gt;之前已经写过一篇比较详细的&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170082845616800211565759%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170082845616800211565759&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-129291207-null-null.nonecase&amp;amp;utm_term=%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;关于逻辑复制的文章&lt;/a&gt;了，这里不会再重复描述一些基础知识。不过难免有些知识点有遗漏，最近发一些有意思的逻辑复制特性。&lt;/p&gt;

&lt;h2 class="relative group"&gt;replica identity与old/new值
 &lt;div id="replica-identity与oldnew值" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e4%b8%8eoldnew%e5%80%bc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;replica identity是用来在逻辑复制期间标识一行数据的。
上面这句话当然没有问题，但是没有解释old和new数据的变化。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;DEFAULT&lt;/code&gt;
Records the old values of the columns of the primary key, if any. This is the default for non-system tables.
&lt;code&gt;USING INDEX&lt;/code&gt; index_name
Records the old values of the columns covered by the named index, that must be unique, not partial, not deferrable, and include only columns marked &lt;code&gt;NOT NULL&lt;/code&gt;. If this index is dropped, the behavior is the same as &lt;code&gt;NOTHING&lt;/code&gt;.
&lt;code&gt;FULL&lt;/code&gt;
Records the old values of all columns in the row.
&lt;code&gt;NOTHING&lt;/code&gt;
Records no information about the old row. This is the default for system tables.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;pg官方文档对于replica identity甚至只解释了old值的情况，例如nothing不复制update/delete都没解释，足见old值的重要性。&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_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;pubtestlzl2&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;pg_recvlogical &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#75715e"&gt;--slot=pubtestlzl2 --start -f recv.sql &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;test_decoding的复制链路正常模拟&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--replica identity默认是d：有主键时用主键；没有主键时为nothing，无法复制update和delete
&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzltest(a bigint &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,b varchar(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; varchar(&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:#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;M&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; lzltest &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;bbbbbb&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzltest &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;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;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;recvlogical输出&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.lzltest: &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt;: a[bigint]:&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;bbbbbb&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&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;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.lzltest: &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;: a[bigint]:&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&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;replica identity为default，更新非主键字段，所有字段只有new值&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzltest &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;111&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:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.lzltest: &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;old&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: a[bigint]:&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;tuple: a[bigint]:&lt;span style="color:#ae81ff"&gt;111&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;bb&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&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;replica identity为default，更新主键时，解析出了主键标识的old和new值，其他字段只有new值&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;M&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; lzltest 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 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;M&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzltest &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;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;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:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.lzltest: &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;old&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: a[bigint]:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;tuple: a[bigint]:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;ccccccccc&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;replica identity设置为full，保留整行数据的old和new值&lt;/p&gt;
&lt;p&gt;无论是default（主键）还是full模式，都会记录所有字段的信息，区别在于是否有old数据。default时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;insert：本身是new数据，当然没有old值，会记录new值的所有字段&lt;/li&gt;
&lt;li&gt;update：记录所有字段的new值，&lt;strong&gt;只有标识字段才有old值（如果有更新标识字段）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;delete：本身是old数据，不一定记录所有字段。同样适用&lt;em&gt;只有标识字段才有old值&lt;/em&gt;，只记录标识位。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;总结：当replica identity为default时，无论什么操作（INSERT,UPDATE,DELTE)，只要是old数据，只记录标识字段；只要是new数据，记录所有字段&lt;/strong&gt;。
把default修改为full时，解析出来的日志量差别不会特别大，因为new数据永远是所有字段，（不考虑&lt;em&gt;全是&lt;/em&gt;delete的场景下）full解析出的日志量小于default时的两倍。&lt;/p&gt;

&lt;h2 class="relative group"&gt;pgoutput不能peek
 &lt;div id="pgoutput不能peek" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pgoutput%e4%b8%8d%e8%83%bdpeek" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;用pgoutput去创建一个复制槽&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;pubtestlzl&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;pgoutput&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;然后去peek或者接收，都失败&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;pubtestlzl&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;pg_recvlogical &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#75715e"&gt;--slot=pubtestlzl --start -f recv.sql &amp;amp;&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;pg_recvlogical: error: could not send replication command &lt;span style="color:#e6db74"&gt;&amp;#34;START_REPLICATION SLOT &amp;#34;&lt;/span&gt;pubtestlzl&lt;span style="color:#e6db74"&gt;&amp;#34; LOGICAL 0/0&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; ERROR: client sent proto_version&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; but we only support protocol &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; or higher
&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;pubtestlzl&amp;#34;&lt;/span&gt;, output plugin &lt;span style="color:#e6db74"&gt;&amp;#34;pgoutput&amp;#34;&lt;/span&gt;, in the startup callback
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_recvlogical: disconnected; waiting &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; seconds to try again&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;不能peek或pg_recvlogical去接收pgoutput的复制槽。由于pgoutput是发布订阅的output plugin，这个plugin不能人工去peek或接收···&lt;/p&gt;

&lt;h2 class="relative group"&gt;发布订阅可以不在pg-pg之间
 &lt;div id="发布订阅可以不在pg-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="#%e5%8f%91%e5%b8%83%e8%ae%a2%e9%98%85%e5%8f%af%e4%bb%a5%e4%b8%8d%e5%9c%a8pg-pg%e4%b9%8b%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;create publication&lt;/code&gt;、&lt;code&gt;create subscription&lt;/code&gt;都是pg内部的命令，也可以用他们来创建pg库之间的链路。
三方软件同样可以使用创建发布，并模拟订阅并创建复制槽。这样比直接创建复制槽要更好，因为可以通过发布管理复制表。&lt;/p&gt;

&lt;h2 class="relative group"&gt;toast和逻辑解析
 &lt;div id="toast和逻辑解析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#toast%e5%92%8c%e9%80%bb%e8%be%91%e8%a7%a3%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;发送toast的字段不会被解析！也就是说整行数据可能只有一部分会传递出来（toast字段本身没有更新的情况下）
正常解析会解析所有字段：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--创建一个test-coding的复制槽
&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_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_dest&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; pg_create_logical_replication_slot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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_dest,&lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A80040E0)
&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; test1(a int &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;,b varchar(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; varchar(&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:#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;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; 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 style="color:#75715e"&gt;--------------+---------------+-----------+--------+----------+-----------+--------+------------+--------+--------------+--------------+---------------------+------------+---------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logical_dest &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;418679&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:#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;872483335&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A80040A8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A80040E0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reserved &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;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&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; test1 &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;qwer&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;915&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; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_dest&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; 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 style="color:#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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8004C78 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483335&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;872483335&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A80103E8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483335&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;872483335&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018B30 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;872483369&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018B30 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;.test1: &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;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018C50 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;872483369&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;5&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;--insert被解析，包含所有字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;update&lt;/span&gt; test1 &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;zxcv&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:#e6db74"&gt;&amp;#39;qwer&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;Time: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;005&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; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_dest&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; 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 style="color:#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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8004C78 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483335&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;872483335&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A80103E8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483335&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;872483335&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018B30 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;872483369&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018B30 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;.test1: &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;qwer&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8018C50 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483369&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;872483369&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A801D018 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483378&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;872483378&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A801D018 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483378&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;.test1: &lt;span style="color:#66d9ef"&gt;UPDATE&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;zxcv&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;qwer&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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A801D098 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483378&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;872483378&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;8&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;--update被解析，包含所有字段&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;正常来说，没有toast时，解析出来的数据是包含该行所有字段的数据的。&lt;/p&gt;
&lt;p&gt;toast解析测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; test1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&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;&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;8&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;091&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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; test1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; varchar(&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;&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;937&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--一个批量random的function
&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;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;replace&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; f_random_str(&lt;span style="color:#66d9ef"&gt;length&lt;/span&gt; INTEGER) &lt;span style="color:#66d9ef"&gt;returns&lt;/span&gt; character varying
&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;LANGUAGE&lt;/span&gt; plpgsql
&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; &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:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DECLARE&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;result&lt;/span&gt; varchar(&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;&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; array_to_string(ARRAY(&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; chr((&lt;span style="color:#ae81ff"&gt;65&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; round(random() &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;)) :: integer)
&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;FROM&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;length&lt;/span&gt;)), &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;result&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;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;result&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;END&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&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;FUNCTION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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; test1 &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,f_random_str(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;),f_random_str(&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;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;--查看是否有toast
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; n.nspname &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;schema&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; s.oid::regclass &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; relname, 
&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; s.reltoastrelid::regclass &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; toast_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; pg_relation_size(s.reltoastrelid) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; toast_size 
&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;FROM&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; pg_class s &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; pg_namespace n 
&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;on&lt;/span&gt; s.relnamespace &lt;span style="color:#f92672"&gt;=&lt;/span&gt; n.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; 
&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; 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;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; reltoastrelid &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;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; n.nspname &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;public&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;ORDER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;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:#ae81ff"&gt;3&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; &lt;span style="color:#66d9ef"&gt;schema&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; toast_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; toast_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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; test1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_toast.pg_toast_418714 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&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;--通过主键进行更新，更新toast字段
&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; test1 &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;zxcv&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 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;&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_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_dest&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; lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xid &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; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A851FD90 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483420&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;872483420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A85216E0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483420&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;.test1: &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt;: a[integer]:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;GIORCXQQWDBGTUNDZXAWMPYOUEGTECWTVQGDQGSPMEPJNPUQIFMESLRASBZWGONETRENDCHLDWVTDWJLTGRYUMFDOWHLEYLUTECPOVCYXFIATLKVEQTHSC&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;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A85218A0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483420&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;872483420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8525CA8 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483429&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;872483429&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8525D50 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483429&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;.test1: &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;: a[integer]:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; b[character varying]:&lt;span style="color:#e6db74"&gt;&amp;#39;zxcv&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;[character varying]:unchanged&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;toast&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;datum
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8525DE0 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;872483429&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;872483429&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有toast的字段c，不涉及更新，没有解析的数据，直接抛出toast数据未变&lt;code&gt;unchanged-toast-datum&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;用wal2json测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pg_create_logical_replication_slot(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_json&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;wal2json&amp;#39;&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 style="color:#75715e"&gt;------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(logical_json,&lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A87CAB58)
&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;update&lt;/span&gt; test1 &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;zxcv&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 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:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;pset format wrapped
&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; format &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; wrapped.
&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;pset columns &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;Target width &lt;span style="color:#66d9ef"&gt;is&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 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_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_json&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 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;lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A87CACF8
&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:#ae81ff"&gt;872483495&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&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:#e6db74"&gt;&amp;#34;change&amp;#34;&lt;/span&gt;:[&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;update&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;public&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;columnnames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columntypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;character varying(3000)&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columnvalues&amp;#34;&lt;/span&gt;:[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;zxcv&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;oldkeys&amp;#34;&lt;/span&gt;:&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;keynames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&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;|&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;keytypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;keyvalues&amp;#34;&lt;/span&gt;:[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&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:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; test1 &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;zxcv&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;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; &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;Time: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;391&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; pg_logical_slot_peek_changes(&lt;span style="color:#e6db74"&gt;&amp;#39;logical_json&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 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;lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A87CACF8
&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:#ae81ff"&gt;872483495&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&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:#e6db74"&gt;&amp;#34;change&amp;#34;&lt;/span&gt;:[&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;update&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;public&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;columnnames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columntypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;character varying(3000)&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columnvalues&amp;#34;&lt;/span&gt;:[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;zxcv&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;oldkeys&amp;#34;&lt;/span&gt;:&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;keynames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&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;|&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;keytypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;keyvalues&amp;#34;&lt;/span&gt;:[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&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:#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;lsn &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;A8CCA0D8
&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:#ae81ff"&gt;872483509&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&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:#e6db74"&gt;&amp;#34;change&amp;#34;&lt;/span&gt;:[&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;update&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;public&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;columnnames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columntypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;character varying(3000)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;character varying(3000)&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;columnvalues&amp;#34;&lt;/span&gt;:[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;zxcv&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;|&lt;/span&gt;.,&lt;span style="color:#e6db74"&gt;&amp;#34;qwer&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;oldkeys&amp;#34;&lt;/span&gt;:&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;keynames&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;keytypes&amp;#34;&lt;/span&gt;:[&lt;span style="color:#e6db74"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;],&lt;span style="color:#e6db74"&gt;&amp;#34;keyvalues&amp;#34;&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;]&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;--更新时，解析出来没有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;wal2json也是一样的效果。&lt;/p&gt;
&lt;p&gt;mysql的参数&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html#sysvar_binlog_row_image" target="_blank" rel="noreferrer"&gt;&lt;code&gt;binlog_row_image&lt;/code&gt;&lt;/a&gt;可以调整binlog是否记录大字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;full&lt;/code&gt; (Log all columns)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minimal&lt;/code&gt; (Log only changed columns, and columns needed to identify rows)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;noblob&lt;/code&gt; (Log all columns, except for unneeded BLOB and TEXT columns)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;pg库完全没有这种控制，默认就是toast字段不解析，无其他选项可以设置~&lt;/p&gt;</content:encoded></item><item><title>PG在还没有pg_class的时候怎么访问基础系统表？</title><link>https://lastdba.com/2024/08/12/pg%E5%9C%A8%E8%BF%98%E6%B2%A1%E6%9C%89pg_class%E7%9A%84%E6%97%B6%E5%80%99%E6%80%8E%E4%B9%88%E8%AE%BF%E9%97%AE%E5%9F%BA%E7%A1%80%E7%B3%BB%E7%BB%9F%E8%A1%A8/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/pg%E5%9C%A8%E8%BF%98%E6%B2%A1%E6%9C%89pg_class%E7%9A%84%E6%97%B6%E5%80%99%E6%80%8E%E4%B9%88%E8%AE%BF%E9%97%AE%E5%9F%BA%E7%A1%80%E7%B3%BB%E7%BB%9F%E8%A1%A8/</guid><description>&lt;p&gt;在没有pg_class的时候，数据库怎么访问系统表？这个问题可以分成两个阶段来看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据库簇初始化，此时一个database都没有，所以怎么构造和访问pg_class等系统表是一个问题&lt;/li&gt;
&lt;li&gt;私有内存初始化系统表。PG的系统表信息是放在backend本地进程上的，backend在初始化的时候又怎么load pg_class？&lt;/li&gt;
&lt;/ol&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%9d%e5%a7%8b%e5%8c%96%e6%95%b0%e6%8d%ae%e5%ad%97%e5%85%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在数据库还没有初始化的时候，明显是不能通过访问数据字典来初始化database、pg_class等等对象的，因为一个库都没有就不能create database，也没有pg_class去查元数据信息。
PG通过bki文件的特殊语言初始化一些数据结构，然后在bootstrap模式初始化一个原始database&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;p&gt;在没有pg_class的时候，数据库怎么访问系统表？这个问题可以分成两个阶段来看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据库簇初始化，此时一个database都没有，所以怎么构造和访问pg_class等系统表是一个问题&lt;/li&gt;
&lt;li&gt;私有内存初始化系统表。PG的系统表信息是放在backend本地进程上的，backend在初始化的时候又怎么load pg_class？&lt;/li&gt;
&lt;/ol&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%9d%e5%a7%8b%e5%8c%96%e6%95%b0%e6%8d%ae%e5%ad%97%e5%85%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在数据库还没有初始化的时候，明显是不能通过访问数据字典来初始化database、pg_class等等对象的，因为一个库都没有就不能create database，也没有pg_class去查元数据信息。
PG通过bki文件的特殊语言初始化一些数据结构，然后在bootstrap模式初始化一个原始database&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;h3 class="relative group"&gt;编译阶段：genbki.h &amp;amp; genbki.pl
 &lt;div id="编译阶段genbkih--genbkipl" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%96%e8%af%91%e9%98%b6%e6%ae%b5genbkih--genbkipl" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;src/include/catalog/genbki.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:#f92672"&gt;*&lt;/span&gt; genbki.h defines &lt;span style="color:#a6e22e"&gt;CATALOG&lt;/span&gt;(), BKI_BOOTSTRAP and related macros
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; so that the catalog header files can be read by the C compiler.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; (These same words are recognized by genbki.pl to build the BKI
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; bootstrap file from these header files.)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;genbki.h&lt;/code&gt;内容很少，主要是为了catalog相关操作的宏定义，以及给KBI bootstrap文件的宏定义。数据字典的头文件基本都包含&lt;code&gt;genbki.h&lt;/code&gt;
&lt;code&gt;genbki.pl&lt;/code&gt;会在编译过程读取&lt;code&gt;/src/include/catalog&lt;/code&gt;目录下的&lt;code&gt;.h&lt;/code&gt;表定义文件（不含&lt;code&gt;pg_*_d.h&lt;/code&gt;），并创建&lt;code&gt;postgres.bki&lt;/code&gt;文件和&lt;code&gt;pg_*_d.h&lt;/code&gt;头文件。
以pg_class为例：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;[postgres@catalog]$ ll |grep pg_class 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r----- 1 postgres postgres 3682 Aug 6 2019 pg_class.dat
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx 1 postgres postgres 86 Apr 8 20:31 pg_class_d.h -&amp;gt; /lzl/soft/postgresql-11.5/src/backend/catalog/pg_class_d.h
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r----- 1 postgres postgres 5219 Aug 6 2019 pg_class.h&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_*_d.h&lt;/code&gt;头文件就是&lt;code&gt;genbki.pl&lt;/code&gt;生成的。&lt;code&gt;pg_*_d.h&lt;/code&gt;文件中都包含下面的一段话：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It has been GENERATED by src/backend/catalog/genbki.pl&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;每个数据字典都有一个结构体&lt;code&gt;typedef struct FormData_*catalogname*&lt;/code&gt;用以存储数据字典的行数据&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;，例如pg_class的&lt;code&gt;FormData_pg_class&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:#a6e22e"&gt;CATALOG&lt;/span&gt;(pg_class,&lt;span style="color:#ae81ff"&gt;1259&lt;/span&gt;,RelationRelationId) BKI_BOOTSTRAP &lt;span style="color:#a6e22e"&gt;BKI_ROWTYPE_OID&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;83&lt;/span&gt;,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&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			oid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* class name */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	NameData	relname;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* OID of namespace containing this class */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			relnamespace &lt;span style="color:#a6e22e"&gt;BKI_DEFAULT&lt;/span&gt;(pg_catalog) &lt;span style="color:#a6e22e"&gt;BKI_LOOKUP&lt;/span&gt;(pg_namespace);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* OID of entry in pg_type for relation&amp;#39;s implicit row type, if any */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			reltype &lt;span style="color:#a6e22e"&gt;BKI_LOOKUP_OPT&lt;/span&gt;(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;/* OID of entry in pg_type for underlying composite type, if any */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			reloftype &lt;span style="color:#a6e22e"&gt;BKI_DEFAULT&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;BKI_LOOKUP_OPT&lt;/span&gt;(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;/* class owner */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			relowner &lt;span style="color:#a6e22e"&gt;BKI_DEFAULT&lt;/span&gt;(POSTGRES) &lt;span style="color:#a6e22e"&gt;BKI_LOOKUP&lt;/span&gt;(pg_authid);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* access-method-specific options */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	text		reloptions[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#a6e22e"&gt;BKI_DEFAULT&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;/* partition bound node tree */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	pg_node_tree relpartbound &lt;span style="color:#a6e22e"&gt;BKI_DEFAULT&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;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} FormData_pg_class;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_class的OID写死了1259，所有字段都在&lt;code&gt;FormData_pg_class&lt;/code&gt;结构体中。
用户存储数据的结构体初始化后，会使用对应的.dat文件插入基础数据。pg_class中会插入4条数据，可以理解为bootstrap item（pg15中的数据字典表有49个）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;{ oid =&amp;gt; &amp;#39;1247&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname =&amp;gt; &amp;#39;pg_type&amp;#39;, reltype =&amp;gt; &amp;#39;pg_type&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ oid =&amp;gt; &amp;#39;1249&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname =&amp;gt; &amp;#39;pg_attribute&amp;#39;, reltype =&amp;gt; &amp;#39;pg_attribute&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ oid =&amp;gt; &amp;#39;1255&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname =&amp;gt; &amp;#39;pg_proc&amp;#39;, reltype =&amp;gt; &amp;#39;pg_proc&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ oid =&amp;gt; &amp;#39;1259&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname =&amp;gt; &amp;#39;pg_class&amp;#39;, reltype =&amp;gt; &amp;#39;pg_class&amp;#39; },&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;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; oid,relname &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; oid::int &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1247&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; oid::int&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1259&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; relname 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;1247&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_type
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1249&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_attribute
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1255&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_proc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1259&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_class&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;初始化database阶段：initdb&amp;amp;postgres.bki
 &lt;div id="初始化database阶段initdbpostgresbki" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%9d%e5%a7%8b%e5%8c%96database%e9%98%b6%e6%ae%b5initdbpostgresbki" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;initdb.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:#f92672"&gt;*&lt;/span&gt; To create template1, we run the &lt;span style="color:#a6e22e"&gt;postgres&lt;/span&gt; (backend) program in bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; mode and feed it data from the postgres.bki library file. After this
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; initial bootstrap phase, some additional stuff is created by normal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; SQL commands fed to a standalone backend. 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以bootstrap模式启动backend并运行postgres.bki脚本，postgres.bki可以在没有任何系统表的情况下，执行相关函数。此后才可以使用正常的SQL文件和启动标准的backend进程。
template1可以称之为bootstrap database了，postgres、template0两个库是在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-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;initialize_data_directory&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;/* Bootstrap template1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;bootstrap_template1&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;make_template0&lt;/span&gt;(cmdfd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;make_postgres&lt;/span&gt;(cmdfd);
&lt;/span&gt;&lt;/span&gt;&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_CMD_CLOSE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;check_ok&lt;/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;有了template1后，&lt;code&gt;make_template0&lt;/code&gt;和&lt;code&gt;make_postgres&lt;/code&gt;创建对应的template0 database和postgres database，直接用一般的SQL语句&lt;code&gt;CREATE DATABASE&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; * copy template1 to 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:#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;make_postgres&lt;/span&gt;(FILE &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cmdfd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;line;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Just as we did for template0, and for the same reasons, assign a fixed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * OID to postgres and select the file_copy strategy.
&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;const&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:#66d9ef"&gt;const&lt;/span&gt; postgres_setup[] &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:#e6db74"&gt;&amp;#34;CREATE DATABASE postgres OID = &amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CppAsString2&lt;/span&gt;(PostgresDbOid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#e6db74"&gt;&amp;#34; STRATEGY = file_copy;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n\n&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 style="color:#e6db74"&gt;&amp;#34;COMMENT ON DATABASE postgres IS &amp;#39;default administrative connection database&amp;#39;;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n\n&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;		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:#66d9ef"&gt;for&lt;/span&gt; (line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; postgres_setup; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;line; line&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;PG_CMD_PUTS&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;line);
&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;backend本地缓存数据字典
 &lt;div id="backend本地缓存数据字典" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#backend%e6%9c%ac%e5%9c%b0%e7%bc%93%e5%ad%98%e6%95%b0%e6%8d%ae%e5%ad%97%e5%85%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PG私有内存的基础知识可参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135541103?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172051768116800222894459%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172051768116800222894459&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-3-135541103-null-null.nonecase&amp;amp;utm_term=%E5%86%85%E5%AD%98%20&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PostgreSQL内存浅析&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;PG的数据字典信息存放在本地backend进程中，非共享。数据字典缓存主要关注的是syscache/catcache和relcache，他们分别缓存系统表和表模式信息。
其中syscache/catcache是用于缓存系统表的，syscache相当于catcache的上层结构。syscache是一个数组，数字中的每个元素对应一个catcache，每个catcache对应一个系统表&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;。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;//PG15.3 SysCacheSize=35
&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; CatCache &lt;span style="color:#f92672"&gt;*&lt;/span&gt;SysCache[SysCacheSize];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg在fork backend的时候调用的是&lt;code&gt;InitPostgres&lt;/code&gt;，其中会调用syscache/catcache和relcache的初始化函数。下面来看看backend的初始化。&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%e5%88%9d%e5%a7%8b%e5%8c%96" 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;struct&lt;/span&gt; cachedesc
&lt;/span&gt;&lt;/span&gt;&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			reloid;			&lt;span style="color:#75715e"&gt;/* OID of the relation being cached */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Oid			indoid;			&lt;span style="color:#75715e"&gt;/* OID of index relation for this 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;int&lt;/span&gt;			nkeys;			&lt;span style="color:#75715e"&gt;/* # of keys needed for cache lookup */&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;			key[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;];			&lt;span style="color:#75715e"&gt;/* attribute numbers of key attrs */&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;			nbuckets;		&lt;span style="color:#75715e"&gt;/* number of hash buckets for this cache */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; cachedesc cacheinfo[] &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;	{RelationRelationId,		&lt;span style="color:#75715e"&gt;/* RELNAMENSP */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		ClassNameNspIndexId,
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			Anum_pg_class_relname,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			Anum_pg_class_relnamespace,
&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 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:#ae81ff"&gt;128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{RelationRelationId,		&lt;span style="color:#75715e"&gt;/* RELOID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		ClassOidIndexId,
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			Anum_pg_class_oid,
&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 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;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:#ae81ff"&gt;128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;例如pg_class，由&lt;code&gt;genbki.pl&lt;/code&gt;生成的&lt;code&gt;pg_class_d.h&lt;/code&gt;中定义&lt;code&gt;Anum_pg_class_oid &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 Anum_pg_class_oid 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;reloid就是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; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; oid,relname &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_class &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; oid::int &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1247&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; oid::int&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1259&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; relname 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;1259&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_class&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;InitCatalogCache&lt;/code&gt;其实是初始化syscache数组，也就是初始化所有的catcache。&lt;code&gt;InitCatalogCache&lt;/code&gt;最终通过&lt;code&gt;InitCatCache&lt;/code&gt;全量初始化CatCache（这里其中一个就有pg_class的)：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;InitCatalogCache&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:#66d9ef"&gt;for&lt;/span&gt; (cacheId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; cacheId &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; SysCacheSize; cacheId&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;		SysCache[cacheId] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;InitCatCache&lt;/span&gt;(cacheId,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 cacheinfo[cacheId].reloid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 cacheinfo[cacheId].indoid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 cacheinfo[cacheId].nkeys,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 cacheinfo[cacheId].key,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;										 cacheinfo[cacheId].nbuckets);
&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;PointerIsValid&lt;/span&gt;(SysCache[cacheId]))
&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 style="color:#e6db74"&gt;&amp;#34;could not initialize cache %u (%d)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				 cacheinfo[cacheId].reloid, cacheId);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Accumulate data for OID lists, too */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		SysCacheRelationOid[SysCacheRelationOidSize&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;			cacheinfo[cacheId].reloid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		SysCacheSupportingRelOid[SysCacheSupportingRelOidSize&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;			cacheinfo[cacheId].reloid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		SysCacheSupportingRelOid[SysCacheSupportingRelOidSize&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;			cacheinfo[cacheId].indoid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* see comments for RelationInvalidatesSnapshotsOnly */&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;RelationInvalidatesSnapshotsOnly&lt;/span&gt;(cacheinfo[cacheId].reloid));
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	CacheInitialized &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;然后来到&lt;code&gt;catcache.c&lt;/code&gt;。
&lt;code&gt;InitCatCache&lt;/code&gt;会开辟内存，并且放到&lt;code&gt;CacheMemoryContext&lt;/code&gt;中管理。它也只是把宏定义的一些oid赋值给对应的catcache，此时还没有open表：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; *		InitCatCache
&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 allocates and initializes a cache for a system catalog relation.
&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, the cache is only partially initialized to avoid opening 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; *	relation. The relation will be opened and the rest of the 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; *	structure initialized on the first access.
&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;CatCache &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;InitCatCache&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			 Oid reloid,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			 Oid indexoid,
&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;			 &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;key,
&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; nbuckets)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	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;	sz &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(CatCache) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; PG_CACHE_LINE_SIZE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (CatCache &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;CACHELINEALIGN&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;palloc0&lt;/span&gt;(sz));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_bucket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;palloc0&lt;/span&gt;(nbuckets &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(dlist_head));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * initialize the cache&amp;#39;s relation information for the relation
&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 to this cache, and initialize some of the new cache&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;	 * other internal fields. But don&amp;#39;t open the relation 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;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; id;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_relname &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;(not known yet)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_reloid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; reloid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_indexoid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; indexoid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_relisshared &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false; &lt;span style="color:#75715e"&gt;/* temporary */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_tupdesc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (TupleDesc) NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_ntup &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;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_nbuckets &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nbuckets;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_nkeys &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nkeys;
&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; (i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; nkeys; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		cp&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cc_keyno[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; key[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#66d9ef"&gt;return&lt;/span&gt; cp;
&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;id是catcache数组元素的编号，赋值的reloid是已知的cacheinfo中的oid，也赋值了cacheinfo中的key[4]，其他信息基本都还不知道，例如relname、tupdesc，因为到这里系统表还没有open。
catcache只有在search的时候才有open的操作，虽然函数名字类似&lt;code&gt;*init*&lt;/code&gt;，不过已经不在初始化的过程中了，相关函数不再这里展示。
syscache/catcache初始化完成后，实际上是没有任何元组信息的。&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%e5%88%9d%e5%a7%8b%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;relcache初始化这篇&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135541103?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172051768116800222894459%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172051768116800222894459&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-3-135541103-null-null.nonecase&amp;amp;utm_term=%E5%86%85%E5%AD%98%20&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PostgreSQL内存浅析&lt;/a&gt;已经讲的比较好了。
relcache初始化由5个阶段:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RelationCacheInitialize - 初始化relcache，初始化为空的&lt;/li&gt;
&lt;li&gt;RelationCacheInitializePhase2 - 初始化共享的catalog，并加载5个global系统表&lt;/li&gt;
&lt;li&gt;RelationCacheInitializePhase3 - 完成初始化relcache，并加载4个基础系统表&lt;/li&gt;
&lt;li&gt;RelationIdGetRelation - 通过relation id获得rel描述&lt;/li&gt;
&lt;li&gt;RelationClose - 关闭一个relation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中&lt;code&gt;RelationCacheInitializePhase2&lt;/code&gt; &lt;code&gt;RelationCacheInitializePhase3&lt;/code&gt; 都有load系统表，他们有先后顺序的必要。
&lt;code&gt;RelationCacheInitializePhase2&lt;/code&gt;有兴趣的可以自行查看函数，也load几个系统表；&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:#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; *		RelationCacheInitializePhase3
&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 is called as soon as the catcache and transaction system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		are functional and we have determined MyDatabaseId. At this point
&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 can actually read data from the database&amp;#39;s system catalogs.
&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 first try to read pre-computed relcache entries from the local
&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 init file. If that&amp;#39;s missing or broken, make phony entries
&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 the minimum set of nailed-in-cache relations. Then (unless
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		bootstrapping) make sure we have entries for the critical system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *		indexes. Once we&amp;#39;ve done all this, we have enough infrastructure 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; *		open any system catalog or use any catcache. The last step is 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; *		rewrite the cache files if 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;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;...
&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;/* In bootstrap mode, the faked-up formrdesc info is all we&amp;#39;ll have */&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&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&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&gt;&lt;/span&gt;&lt;span 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;IsBootstrapProcessingMode&lt;/code&gt;其实是专门为bootstrap模式定制的判断，一般的backend是不满足这个条件的。
&lt;code&gt;load_relcache_init_file(false)&lt;/code&gt;尝试从initfile中加载系统表信息，&lt;code&gt;load_relcache_init_file(false)&lt;/code&gt;传入的是&lt;code&gt;false&lt;/code&gt;表示是私有initfile，不是共享initfile：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#ae81ff"&gt;16384&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pgdata&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;data15_6879&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;16384&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--粗糙一点看。strings会忽略一部分信息，但是表和列名可以看到
&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:#ae81ff"&gt;16384&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; strings pg_internal.init &lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep pg_class
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class_oid_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class_relname_nsp_index
&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:#ae81ff"&gt;16384&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; strings pg_internal.init &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;pg_class|relname&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class_oid_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relname
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relnamespace
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_class_relname_nsp_index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relname
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;relnamespace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果initfile损坏或者没有，那么加载initfile失败进入判断，去load 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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	//跟2阶段差不多，加载更多的系统表描述
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	if (IsBootstrapProcessingMode() ||
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		!load_relcache_init_file(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 = 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;		formrdesc(&amp;#34;pg_class&amp;#34;, 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;		formrdesc(&amp;#34;pg_attribute&amp;#34;, 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;		formrdesc(&amp;#34;pg_proc&amp;#34;, 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;		formrdesc(&amp;#34;pg_type&amp;#34;, 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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有了pg_class 4个基础表，后面加载系统表信息一切都很简单了&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;《PostgreSQL内核分析》第2，3章&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;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/system-catalog-declarations.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/system-catalog-declarations.html&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;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135541103?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172051768116800222894459%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=172051768116800222894459&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-3-135541103-null-null.nonecase&amp;amp;utm_term=%E5%86%85%E5%AD%98%20&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PostgreSQL内存浅析&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;/ol&gt;
&lt;/div&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%E9%9D%A2%E8%AF%95%E9%A2%98-%E7%81%BF%E6%80%BB%E9%A2%98/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/postgresql%E9%9D%A2%E8%AF%95%E9%A2%98-%E7%81%BF%E6%80%BB%E9%A2%98/</guid><description>&lt;p&gt;面试题来源 ：PostgreSQL学徒 &lt;a href="https://mp.weixin.qq.com/s/DCmO1E31JAbec1M05y2_UQ" target="_blank" rel="noreferrer"&gt;PostgreSQL面试题集锦&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;已有的答案：Hehuyi_In &lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/128885660?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170641029516800227443317%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&amp;amp;request_id=170641029516800227443317&amp;amp;biz_id=0&amp;amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-128885660-null-null.142%5ev99%5epc_search_result_base6&amp;amp;utm_term=pg%E9%9D%A2%E8%AF%95%E9%A2%98&amp;amp;spm=1018.2226.3001.4187" target="_blank" rel="noreferrer"&gt;《PostgreSQL面试题集锦》学习与回答&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;一、MVCC 实现机制以及和 Oracle 的差异
 &lt;div id="一mvcc-实现机制以及和-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="#%e4%b8%80mvcc-%e5%ae%9e%e7%8e%b0%e6%9c%ba%e5%88%b6%e4%bb%a5%e5%8f%8a%e5%92%8c-oracle-%e7%9a%84%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ORACLE，MYSQL都是使用的UNDO来实现多版本并发控制，undo条目记录在从&lt;strong&gt;额外&lt;/strong&gt;的undo表空间中，如果UNDO段不够会报ora-01555的错误。



&lt;img src="https://lastdba.com/img/csdn/fec3e1c0263f.png" alt="在这里插入图片描述" /&gt;
&lt;a href="https://www.slideshare.net/AmitBhalla2/less10-undo-15946188" target="_blank" rel="noreferrer"&gt;https://www.slideshare.net/AmitBhalla2/less10-undo-15946188&lt;/a&gt;&lt;/p&gt;</description><content:encoded>&lt;p&gt;面试题来源 ：PostgreSQL学徒 &lt;a href="https://mp.weixin.qq.com/s/DCmO1E31JAbec1M05y2_UQ" target="_blank" rel="noreferrer"&gt;PostgreSQL面试题集锦&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;已有的答案：Hehuyi_In &lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/128885660?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170641029516800227443317%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&amp;amp;request_id=170641029516800227443317&amp;amp;biz_id=0&amp;amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-128885660-null-null.142%5ev99%5epc_search_result_base6&amp;amp;utm_term=pg%E9%9D%A2%E8%AF%95%E9%A2%98&amp;amp;spm=1018.2226.3001.4187" target="_blank" rel="noreferrer"&gt;《PostgreSQL面试题集锦》学习与回答&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;一、MVCC 实现机制以及和 Oracle 的差异
 &lt;div id="一mvcc-实现机制以及和-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="#%e4%b8%80mvcc-%e5%ae%9e%e7%8e%b0%e6%9c%ba%e5%88%b6%e4%bb%a5%e5%8f%8a%e5%92%8c-oracle-%e7%9a%84%e5%b7%ae%e5%bc%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ORACLE，MYSQL都是使用的UNDO来实现多版本并发控制，undo条目记录在从&lt;strong&gt;额外&lt;/strong&gt;的undo表空间中，如果UNDO段不够会报ora-01555的错误。



&lt;img src="https://lastdba.com/img/csdn/fec3e1c0263f.png" alt="在这里插入图片描述" /&gt;
&lt;a href="https://www.slideshare.net/AmitBhalla2/less10-undo-15946188" target="_blank" rel="noreferrer"&gt;https://www.slideshare.net/AmitBhalla2/less10-undo-15946188&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL没有undo机制，为了保证事务回滚，旧的元组仍然在表上。如update会新插入一行数据，老的数据还保留在原来的位置，然后通过元组头、clog等来判断新旧元组哪个是有效的。这些元组头上的可见性信息包括xmin、xmax、cmin、cmax、infomask、infomask2，存储在元组头&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f34dabdc091c.png" alt="在这里插入图片描述" /&gt;
&lt;a href="https://www.interdb.jp/pg/pgsql05/03.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05/03.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;优劣势：undo方案需要额外的undo空间，空间管理比较简单，问题在于大事务回退时非常麻烦，需要将undo段回滚。新增元组方案的大事务回滚非常快，不过该方式会有死元组问题，导致需要引入vacuum机制来清理死元组。vacuum freeze本身跟清理死元组没什么关系（但都是vacuum进程），freeze是为了防止事务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="#%e4%ba%8c%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e6%9c%89%e8%a1%a8%e8%86%a8%e8%83%80%e5%8f%8a%e8%a1%a8%e8%86%a8%e8%83%80%e7%9a%84%e5%8d%b1%e5%ae%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;为什么有表膨胀？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同上，因为PG特殊的MVCC机制，delete不会真的删除元组，update相当于delete+insert，旧元组本身不能通过DML语句来删除，这样就只有“涨”空间没有“清理”空间，这就是表膨胀。此时一般需要vacuum来清理死元组，把空间标记为可用，下次写入时可以用到这部分空间；或者vacuum full等方式重写表，让表变得更加紧凑。&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;进而引起sql性能降低&lt;/li&gt;
&lt;li&gt;表过大会也会导致vacuum清理时间变成长；vacuum full阻塞时间也会变长，不过可以通过pg_repack来代替vacuum full，减少阻塞时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;处理表膨胀：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.手动vacuum&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不会阻塞查询和DML业务&lt;/li&gt;
&lt;li&gt;不会立即回收空间，只是把空间标记为可用&lt;/li&gt;
&lt;li&gt;如果表的最后一个page没有元组了，这个page会被truncate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4bcffb429099.png" alt="在这里插入图片描述" /&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;2.autovacuum&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;autovacuum会根据需要自动调用vacuum进行concurrently清理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.手动vacuum full&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8级锁，阻塞一切&lt;/li&gt;
&lt;li&gt;表完全重写，操作系统上对应的文件会被清理和重建&lt;/li&gt;
&lt;li&gt;重建索引、FSM（可用空间文件）、VM （page可见性文件）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5c9458f68c2e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;4.pg_repack等手动重建表&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pg_repack只有在最后切换表的时候有短暂的锁&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;p&gt;一般来说autovacuum可处理表膨胀，不过有些场景下清理进行的可能不顺利：&lt;/p&gt;
&lt;p&gt;1.autovacuum worker没跑起来&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;autovacuum&lt;/code&gt;,&lt;code&gt;track_counts&lt;/code&gt;参数均必须打开，autovacuum才会工作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autovacuum_max_workers&lt;/code&gt;设置足够work进程数上限，可能同一时间需要多个work清理多个表&lt;/li&gt;
&lt;li&gt;没有到达表的vacuum阈值&amp;ndash;delete和update的行数：阈值=&lt;code&gt;autovacuum_vacuum_threshold&lt;/code&gt;+&lt;code&gt;autovacuum_vacuum_scale_factor&lt;/code&gt;*tuples&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autovacuum_vacuum_insert_threshold&lt;/code&gt;和&lt;code&gt;autovacuum_vacuum_insert_scale_factor&lt;/code&gt;表示insert的阈值，算法同上。insert触发的vacuum阈值理论上跟表膨胀清不清理没什么关系，因为insert不会产生死元组。不过为了防止一次来不及处理回卷问题，pg13新增了这个参数（参考 &lt;a href="https://www.cybertec-postgresql.com/en/postgresql-autovacuum-insert-only-tables/" target="_blank" rel="noreferrer"&gt;postgresql-autovacuum-insert-only-tables&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autovacuum_naptime&lt;/code&gt;表示autovacuum launcher的执行周期。比如该参数设置的特别大，可能造成&lt;code&gt;autovacuum_max_workers&lt;/code&gt;足够，并且有表达到清理阈值，但launcher没有唤醒worker的情况&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vacuum_defer_cleanup_age&lt;/code&gt;延迟多少个事务再进行vacuum清理（本身是为了缓解备库环境查询冲突而设置的参数，因为有&lt;code&gt;hot_standby_feedback&lt;/code&gt;和复制槽，pg16已删除该参数）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.关闭或调整cost-based vacuuming让autovacuum跑的更快&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于为了降低vacuum对IO的影响，可能打开了cost-based vacuuming功能，vacuum/autovacuum达到cost limit时睡眠&lt;code&gt;autovacuum_vacuum_cost_delay&lt;/code&gt;(或&lt;code&gt;vacuum_cost_delay&lt;/code&gt;）毫秒。&lt;code&gt;vacuum_cost_delay&lt;/code&gt;默认0表示关闭cost-based vacuuming功能，&lt;code&gt;autovacuum_vacuum_cost_delay&lt;/code&gt;为-1表示使用&lt;code&gt;vacuum_cost_delay&lt;/code&gt;参数。应该关闭delay或者将delay值调小&lt;/li&gt;
&lt;li&gt;如果开启了cost-based vacuuming，应合理调大&lt;code&gt;vacuum_cost_limit&lt;/code&gt;的触发睡眠值，以及调小计算到limit里的&lt;code&gt;vacuum_cost_page_dirty&lt;/code&gt;,&lt;code&gt;vacuum_cost_page_miss&lt;/code&gt;,&lt;code&gt;vacuum_cost_page_hit&lt;/code&gt;参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.表上有事务阻止vacuum运行&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务的长事务没有结束。业务侧事务不要跑太长时间；数据库侧可通过断开连接的方式杀掉会话1).手动kill 2).设置idle_in_transaction_session_timeout限制事务idle过长 3).设置old_snapshot_threshold限制SQL执行过长（PG14以前不建议打开）&lt;/li&gt;
&lt;li&gt;未关闭的游标&lt;/li&gt;
&lt;li&gt;hot_standby_feedback打开后，主库记录catalog_xmin，备库长查询阻止主库回收（参考：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/120000817?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170640708116800225535776%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170640708116800225535776&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-120000817-null-null.nonecase&amp;amp;utm_term=%E6%9F%A5%E8%AF%A2%E5%86%B2%E7%AA%81&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;流复制-查询冲突&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;删除不要的复制槽&lt;/li&gt;
&lt;li&gt;孤儿事务。prepared事务是PG内部的显示开起的2PC事务，prepared事务如果开启后没有完成，prepared事务又与会话无关，导致孤儿事务无限期阻塞（参考：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130783427?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170640828316800188543009%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170640828316800188543009&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-130783427-null-null.nonecase&amp;amp;utm_term=2PC&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg事务：2PC&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;pg_dump逻辑备份开启隐式repeatable read隔离级别，事务未结束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4.性能方面&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maintenance_work_mem&lt;/code&gt;参数是vacuum等维护操作使用的内存，默认64MB可以再调大一点。或者用&lt;code&gt;autovacuum_work_mem&lt;/code&gt;参数单独设置autovacuum worker的内存，&lt;code&gt;autovacuum_work_mem&lt;/code&gt;默认-1表示使用&lt;code&gt;maintenance_work_mem&lt;/code&gt;参数的设置&lt;/li&gt;
&lt;li&gt;一般大表的vacuum会特别慢，由于同一表上的vacuum无法并行，可以将大表改造为分区表，vacuum可以在各个分区上并行执行&lt;/li&gt;
&lt;li&gt;良好的IO系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;5.调整表上的autovacuum参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局的autovacuum相关参数设置可能不适应于某些特殊业务表，可调整表上的autovacuum相关参数，提高触发vacuum几率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;6.手动vacuum&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;autovacuum总体上是难预料的，对于特殊的业务表可手动vacuum&lt;/li&gt;
&lt;li&gt;在业务低峰期手动执行vacuum命令，可附带freeze，analyze一起使用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上可以处理99.99%的表膨胀问题，有一种表膨胀上面的方法是难以处理的：&lt;strong&gt;cost-based vacuuming关闭的情况下，autovacuum清理死元组速度赶不上生成速度&lt;/strong&gt;。本质上是因为update（或者insert+delete)事务并发太多，这次的vacuum还没来得及清理出之前的可用空间，就有大量update生成新的空间和死元组，导致表不断膨胀。解决办法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;改造为分区表以增加vacuum并行度，前提是update需要打散到各个分区上，不然没有意义&lt;/li&gt;
&lt;li&gt;低峰期执行vacuum full或者pg_repack，彻底清理表的空洞。&lt;/li&gt;
&lt;li&gt;不太可能有24h高并发的表，如果有应该改造为多表写入，或者搬到redis等缓存系统上&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s?__biz=MzUyOTAyMzMyNg==&amp;amp;mid=2247485791&amp;amp;idx=1&amp;amp;sn=24ef88bd19d923d60fdf1a8969577fb0&amp;amp;chksm=fa66216ecd11a8789ee0a9a4b7e850d98086bf3ae542aad814788bd8f262dd675be92fa7c5db&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=0204hKVlhPOQa19uoxv7u3Ch&amp;amp;sharer_sharetime=1675514289096&amp;amp;sharer_shareid=1a32625a0cee9a1f3987aa62eea3fa03&amp;amp;exportkey=n_ChQIAhIQQ4H0Z5qjGf21zcqa8OvAKxKZAgIE97dBBAEAAAAAAMSqIP5cR5AAAAAOpnltbLcz9gKNyK89dVj0uMOj41SOhYI%2BA5Y3sbSQytf8OotyHqqED8OFC4Tealz7gt91%2FbaCaExVHDNExUGj%2FFrrrwQo6a3qGtJdUptL6vyG2pb9G0NKzNyuv1JbQq%2FLbX9LgTeCARhtml2oCiD%2FLpZJmHpbgRccjrjZCVmQ6oCACKTTSh1P2mfSJbPk7MwCYzdshC3CxYaXemFbwoL9u9tM2H36%2FYBpOLW4wJiSI54CgHscZ%2FeSZfNwaHsn99iojWcG11b204NEjkMmpFgKOq%2F%2FJDMJu0ZwZaQRaLfoLZ5H%2FOgmJOeUQMrp%2Bc7A7UROn7%2BWTGJct6i3l9jJd44OTjyu&amp;amp;acctmode=0&amp;amp;pass_ticket=UiziakVvQcg3ztgfB%2Bovewae4j0ijakENPH%2BRT8lyhXyARWs5hjeT%2FDsPN2ithp8%2B5Wqbk2ySDdewyfjSC2BMg%3D%3D&amp;amp;wx_header=0#rd" target="_blank" rel="noreferrer"&gt;揭开表膨胀的神秘面纱&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;a href="https://www.postgresql.org/docs/16/routine-vacuuming.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/routine-vacuuming.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/runtime-config-autovacuum.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/runtime-config-autovacuum.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/runtime-config-resource.html#GUC-VACUUM-COST-DELAY" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/runtime-config-resource.html#GUC-VACUUM-COST-DELAY&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="#%e4%b8%89%e9%95%bf%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%8d%b1%e5%ae%b3%e4%bb%a5%e5%8f%8a%e5%a6%82%e4%bd%95%e6%ba%af%e6%ba%90%e9%95%bf%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;一般的查询不会生成事务ID，而是虚拟事务ID（vxid)，虚拟事务ID由backendID和backend本地计数器组成，与事务ID(XID)没有关系（参考：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782577?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22130782577%22%2C%22source%22%3A%22qq_40687433%22%7D" target="_blank" rel="noreferrer"&gt;pg事务：事务ID&lt;/a&gt;）。不过查询虽然不会生成事务ID，但是它会持有快照以保证可见性检查，快照中包含元组xmin等信息（参考：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130783265?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170643483116800192217094%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170643483116800192217094&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-130783265-null-null.nonecase&amp;amp;utm_term=%E5%8F%AF%E8%A7%81%E6%80%A7%E6%A3%80%E6%9F%A5&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg事务：可见性检查&lt;/a&gt;，&lt;a href="https://liuzhilong.blog.csdn.net/article/details/130783036" target="_blank" rel="noreferrer"&gt;pg事务：快照&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9b24ddaad8e7.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://www.interdb.jp/pg/pgsql05/05.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql05/05.html&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;所以，长事务问题不仅包含DML语句也包含查询语句，不过两者的申请的锁是不同的&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长事务的危害&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;阻碍vacuum回收，导致表膨胀、导致过多的空间占用、导致SQL性能下降&lt;/li&gt;
&lt;li&gt;阻碍其他锁申请，例如DDL执行前必须检查表上是否有长事务，不然长期申请不到更高级别的锁，导致锁放大&lt;/li&gt;
&lt;li&gt;长事务会导致create index currently失败，留下失效索引&lt;/li&gt;
&lt;li&gt;占用连接池（当然一般主要是长连接问题导致）&lt;/li&gt;
&lt;li&gt;逻辑解析数据落盘导致复制延迟，与大事务也有关系（参考：&lt;a href="https://mp.csdn.net/mp_blog/creation/editor/129291207" target="_blank" rel="noreferrer"&gt;pg内功修炼：逻辑复制&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;一个长事务和一个savepoint子事务也可能造成查询库性能断崖（参考： &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;Why we spent the last month eliminating PostgreSQL subtransactions&lt;/a&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;pg_stat_activity查看xact_start事务开始时间，state_change查看事务是否还在运行&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%9b%9b%e5%ad%90%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%8d%b1%e5%ae%b3%e5%92%8c%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;子事务的危害：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;事务ID消耗过快，过早的处理事务回卷问题。每个子事务都会消耗一个xid&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PGPROC_MAX_CACHED_SUBXIDS溢出，导致性能下降。每个backend都有子事务cache为&lt;code&gt;PGPROC_MAX_CACHED_SUBXIDS&lt;/code&gt;，固定64个子事务（源码写死），超过64个子事务会溢出到&lt;code&gt;pg_subtrans&lt;/code&gt;目录（参考：&lt;a href="https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful" target="_blank" rel="noreferrer"&gt;PostgreSQL Subtransactions Considered Harmful&lt;/a&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子事务和for update显示行锁一起使用，导致数据库性能急剧下降 （参考：&lt;a href="https://buttondown.email/nelhage/archive/notes-on-some-postgresql-implementation-details/" target="_blank" rel="noreferrer"&gt;Notes on some PostgreSQL implementation details&lt;/a&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个长事务和一个savepoint子事务也可能造成查询库性能断崖（参考：&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;Why we spent the last month eliminating PostgreSQL subtransactions&lt;/a&gt;&lt;/p&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;li&gt;如果仍有子事务，子事务设置不要超过64个，最好是更低&lt;/li&gt;
&lt;li&gt;除了显示savepoint使用子事务，excetpion、框架、工具中同样会产生子事务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://liuzhilong.blog.csdn.net/article/details/130783474" target="_blank" rel="noreferrer"&gt;pg事务：子事务&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;五、表结构变更哪些操作是非 online 的
 &lt;div id="五表结构变更哪些操作是非-online-的" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%94%e8%a1%a8%e7%bb%93%e6%9e%84%e5%8f%98%e6%9b%b4%e5%93%aa%e4%ba%9b%e6%93%8d%e4%bd%9c%e6%98%af%e9%9d%9e-online-%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;表结构变更都是非online的，因为所有表结构变更（alter table）都需要申请8级锁，只是有些表结构变更本身需要很长时间或者变更后业务跑的慢。所以这个问题可以转化为下面下面三个问题：&lt;/p&gt;
&lt;p&gt;对索引是否有影响？对统计信息是否有影响？是否要重写表导致长期持有8级锁？&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7b272ed64104.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/cg1tXiifC83p0hWMs92Cxw" target="_blank" rel="noreferrer"&gt;表结构变更精华图&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;结合上面的信息，汇总记忆：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除字段可立即完成，但需要考虑复合索引和多列统计信息失效，以免引起sql性能雪崩&lt;/li&gt;
&lt;li&gt;添加字段只考虑带默认值：1)pg10以前需要带默认值需要重写表 2)pg11以后 默认值为volatile函数需要重写表。另外添加字段后不会立即有统计信息&lt;/li&gt;
&lt;li&gt;修改自动长度：小改大，除int到bigint，都不需要重写表；大改小需要重写表；列统计信息失效&lt;/li&gt;
&lt;li&gt;修改字段类型：&lt;em&gt;表重写&lt;/em&gt;；统计信息失效。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;已有字段添加约束会扫描表，需要注意扫描时间&lt;/em&gt;，（如&lt;code&gt;ADD CONSTRAINT&lt;/code&gt;,&lt;code&gt;SET NOT NULL&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;em&gt;已有字段添加默认值立即完成&lt;/em&gt;（如&lt;code&gt;SET/DROP DEFAULT&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;em&gt;SET { LOGGED | UNLOGGED } 会重写表&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;表的storage_parameter变更，具体看变更什么参数。比如fillfactor、autovacuum相关参数是online的非8级锁，立即完成（参考：[Storage Parameters）&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;六、物理备份需要注意什么（pg_start_backup）
 &lt;div id="六物理备份需要注意什么pg_start_backup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%ad%e7%89%a9%e7%90%86%e5%a4%87%e4%bb%bd%e9%9c%80%e8%a6%81%e6%b3%a8%e6%84%8f%e4%bb%80%e4%b9%88pg_start_backup" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a226f3f1899f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://postgrespro.com/media/2022/03/24/pgpro-backup-methods%20%281%29.pdf" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/media/2022/03/24/pgpro-backup-methods%20(1).pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pg物理备份：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;块层面的备份，一般不支持单独的database备份（pg_probackup除外）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;排他模式没有必要存在，原因：1) 只能在主库备份 2)不允许并行备份 3)创建的backup label可能阻止主库实例恢复 4）功能上跟非排他备份没有区别。PG9.6开始支持非排他模式，PG15移除排他模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果显示使用pg_start_backup()，应显示使用pg_stop_backup()关闭备份模式（PG15后函数名有些区别）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;备份中FPI功能会强制打开，即使没有把full_page_writes设为on&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有工具（maybe），备份开始前都会调用pg_stop_backup()做一个checkpoint写脏数据，并备份从备份开始到结束的所有wal日志，哪怕是备份过程中数据库新生成的WAL，以保证数据一致性和PITR&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;pg_basebackup&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;原生自带&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;封装pg_start_backup和pg_stop_backup命令&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pg17开始支持增量备份，支持合并备份集&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;占用一个walsender进程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;pg_probackup&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;非常强大，支持增量备份、增量恢复、并行、合并被集、备份集校验、远程备份、恢复指定database等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BUG：寻址空间不能超过4GB，可通过修改源码修复&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;pgBackRest&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;也非常强大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大前提：必须备份机到数据库主机的配置ssh&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://developer.aliyun.com/article/59359" target="_blank" rel="noreferrer"&gt;https://developer.aliyun.com/article/59359&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.enterprisedb.com/blog/exclusive-backup-mode-finally-removed-postgres-15" target="_blank" rel="noreferrer"&gt;https://www.enterprisedb.com/blog/exclusive-backup-mode-finally-removed-postgres-15&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/MasaoFujii/pg_exclusive_backup" target="_blank" rel="noreferrer"&gt;https://github.com/MasaoFujii/pg_exclusive_backup&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/postgrespro/pg_probackup" target="_blank" rel="noreferrer"&gt;https://github.com/postgrespro/pg_probackup&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pgbackrest.org/user-guide.html" target="_blank" rel="noreferrer"&gt;https://pgbackrest.org/user-guide.html&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="#%e4%b8%83%e9%80%bb%e8%be%91%e5%a4%87%e4%bb%bd%e6%98%af%e5%a6%82%e4%bd%95%e7%a1%ae%e4%bf%9d%e4%b8%80%e8%87%b4%e6%80%a7%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;pg_dump的一次完整的备份是在一个事务中完成的, 事务隔离级别为serializable 或者 repeatable read&lt;/li&gt;
&lt;li&gt;pg_dump在备份数据开始前, 需要对进行备份的对象加ACCESS SHARE锁，防止表被删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外逻辑备份还需注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;导出时需要特别注意是否有锁冲突&lt;/li&gt;
&lt;li&gt;如果有ddl需求，应考虑不要备份全库或长时间备份；或者把备份任务拆开为多个，比如一次一个表多次调用pg_dump&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://developer.aliyun.com/article/14582" target="_blank" rel="noreferrer"&gt;https://developer.aliyun.com/article/14582&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;八、WAL 堆积的原因有哪些
 &lt;div id="八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="#%e5%85%abwal-%e5%a0%86%e7%a7%af%e7%9a%84%e5%8e%9f%e5%9b%a0%e6%9c%89%e5%93%aa%e4%ba%9b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;失效的复制槽&lt;/li&gt;
&lt;li&gt;逻辑复制有长事务&lt;/li&gt;
&lt;li&gt;过大的wal_keep_size&lt;/li&gt;
&lt;li&gt;过小的archive_timeout。强制切换wal并归档，相当于pg_switch_xlog()切换日志+归档&lt;/li&gt;
&lt;li&gt;归档失败会生成.ready文件&lt;/li&gt;
&lt;li&gt;单进程归档，归档速度跟不上&lt;/li&gt;
&lt;li&gt;FPI全页写（应检查checkpoint是否过于频繁、UUID等离散写行为）&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%b9%9d%e9%95%bf%e8%bf%9e%e6%8e%a5%e7%9a%84%e5%8d%b1%e5%ae%b3%e6%98%af%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pg在获得快照数据的时候，需要检索所有backend进程的事务状态，过多的连接导致性能下降（建议连接数不超过1000，pg14有优化但是仍不建议过多连接）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;relcache/syscache不会释放缓存的元数据，且每个进程都单独缓存，导致内存消耗较多&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&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="#%e5%8d%81infomask-%e6%a0%87%e5%bf%97%e4%bd%8d%e7%9a%84%e4%bd%9c%e7%94%a8%e6%98%af%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;infomask提供了事务、锁、元组状态等信息，比如事务是否提交、终止，行锁信息、HOT信息、列个数等等，非常多信息&lt;/li&gt;
&lt;li&gt;header中有两个infomask：&lt;code&gt;infomask&lt;/code&gt;和&lt;code&gt;infomask2&lt;/code&gt;。他们存储的信息有所不同，通过不同的位代表不同的含义&lt;/li&gt;
&lt;li&gt;hitbits的事务信息也会写入infomask，这样可以不用访问clog，仅访问元组头信息就可以知道元组的插入、删除任务是否完成、是否先于或后于本事务以判断元组的可见性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://liuzhilong.blog.csdn.net/article/details/130782857?spm=1001.2014.3001.5502" target="_blank" rel="noreferrer"&gt;pg事务：事务相关元组结构&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%8d%81%e4%b8%80%e7%a9%ba%e5%80%bc%e6%98%af%e5%a6%82%e4%bd%95%e5%ad%98%e5%82%a8%e7%9a%84%e4%bb%a5%e5%8f%8a%e7%b4%a2%e5%bc%95%e6%98%af%e5%90%a6%e5%ad%98%e5%82%a8%e7%a9%ba%e5%80%bc" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;空值如何存储：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f3fc29d1f5cd.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在tuple header中存储null，而不是tuple的data段&lt;/li&gt;
&lt;li&gt;infomask中有一位标记该元组是否有NULL&lt;/li&gt;
&lt;li&gt;t_bits有n*8位（n为整数，如10列的表有16位的t_bits），以位图来代表哪一列是null的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;索引是否存储空值：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;postgresql的索引存储空值，oracle索引不存空值&lt;/li&gt;
&lt;li&gt;存储的位置取决于(NULLS FIRST or NULLS LAST)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.highgo.ca/2020/10/20/the-way-to-store-null-value-in-pg-record/" target="_blank" rel="noreferrer"&gt;https://www.highgo.ca/2020/10/20/the-way-to-store-null-value-in-pg-record/&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;十二、为什么需要有全页写（full_page_write）
 &lt;div id="十二为什么需要有全页写full_page_write" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%81%e4%ba%8c%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e6%9c%89%e5%85%a8%e9%a1%b5%e5%86%99full_page_write" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;官方文档对full page write介绍比较笼统：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This is needed because a page write that is in process during an operating system crash might be only partially completed, leading to an on-disk page that contains a mix of old and new data. The row-level change data normally stored in WAL will not be enough to completely restore such a page during post-crash recovery. Storing the full page image guarantees that the page can be correctly restored, but at the price of increasing the amount of data that must be written to WAL. (Because WAL replay always starts from a checkpoint, it is sufficient to do this during the first change of each page after a checkpoint&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;操作系统文件页一般为4k，pg的page一般为8k，可能发生partial write的情况，导致磁盘上的一个数据页既包含老数据也包含新数据，这会导致数据恢复时发生数据丢失，所以需要引入引入全页写机制。&lt;/p&gt;
&lt;p&gt;partial write跟磁盘有很大关系，能详细回答这个问题是比较难的，参考&lt;a href="http://www.killdb.com/2020/04/05/double_write_partial_write_oracle_mysql_postgresql/" target="_blank" rel="noreferrer"&gt;roger这篇文章&lt;/a&gt;，总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;partial write与磁盘是否支持原子写有关系&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;partial write与操作系统块大小与数据库块大小是否匹配有关系。oracle、pg的块默认8k，mysql默认16k，os默认4k，数据库的一次最小IO对于操作系统来讲需要调用多次完成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于PG来说，如果&lt;strong&gt;数据页&lt;/strong&gt;出现partial write，可根据wal中的full page进行恢复&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于mysql，有double write机制。double write buffer是磁盘上的空间，顺序写；在写数据前先顺序写到这里以缓解partial write问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于oracle，做了很多工作不过没有一个明显的解决方案。但是oracle支持块级恢复以替换损坏的数据块。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同的DB都采用了不同的方案来减少partial write，比如PG把整个数据页写到wal日志中，但是这带来了wal写放大问题。当然这可以通过一些方式缓解wal写放大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;怎么完美解决partial write问题？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持原子写的设备&lt;/li&gt;
&lt;li&gt;OS最小IO与数据库最小IO保持一致&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://www.killdb.com/2020/04/05/double_write_partial_write_oracle_mysql_postgresql/" target="_blank" rel="noreferrer"&gt;http://www.killdb.com/2020/04/05/double_write_partial_write_oracle_mysql_postgresql/&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%8d%81%e4%b8%89%e7%b4%a2%e5%bc%95%e5%a4%b1%e6%95%88%e7%9a%84%e5%90%84%e7%a7%8d%e5%8e%9f%e5%9b%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;索引失效：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;create index concurrently时因为死锁或唯一索引检查失败会留下一个invalid索引，invalid索引也会被更新&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分区表主表上索引invalid，代表某些分区有索引某些分区没有（参考：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170670806616800184170018%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170670806616800184170018&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-132525655-null-null.nonecase&amp;amp;utm_term=%E5%88%86%E5%8C%BA%E8%A1%A8&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;）&lt;/p&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;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;软解析，前5次缓存了其他执行计划&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最左原则&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据过少，如hash、全表不比索引慢&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;函数（除非对应immutable函数索引），隐式转换、运算、like左边带%···&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据类型不一致&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;字符集不一致（pg里问题不大，因为pg中database一旦创建字符集不能更改，一个database下的数据是同一字符集，不同database正常不能交叉访问）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sql的collation排序与索引collation排序不一致&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;like只能使用collation C或pattern索引（参考：&lt;a href="https://liuzhilong.blog.csdn.net/article/details/132651899?spm=1001.2014.3001.5502&amp;amp;ydreferer=aHR0cHM6Ly9saXV6aGlsb25nLmJsb2cuY3Nkbi5uZXQvP3R5cGU9YmxvZw%3D%3D" target="_blank" rel="noreferrer"&gt;PostgreSQL本地化&lt;/a&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;correlation较大，索引的逻辑顺序与数据的物理顺序相关性，通过索引访问较为离散的数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;limit xx ordr by column1、min/max等需要取TOP N的场景，优化器选择了其他索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;十四、commit log 的作用
 &lt;div id="十四commit-log-的作用" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%81%e5%9b%9bcommit-log-%e7%9a%84%e4%bd%9c%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;commit log是为了记录事务状态的。在表的下一次可见性检查时，触发hintbits，将clog的事务状态写入到元组头。&lt;/p&gt;
&lt;p&gt;**为什么不能将事务状态立即写入元组头？**hintbits立即更新性能非常差，所以将事务状态先放在clog，减少PGXACT的争用，以提升性能&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782857?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170670998016800182715738%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170670998016800182715738&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;pg事务：事务相关元组结构&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%8d%81%e4%ba%94%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e8%bf%9e%e6%8e%a5%e6%96%b9%e5%bc%8f%e4%bb%a5%e5%8f%8a%e5%90%84%e8%87%aa%e9%80%82%e7%94%a8%e7%9a%84%e5%9c%ba%e6%99%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1.1 Nested Loop Join&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/20abc423c1e9.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;lzldb&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl1,t3 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; lzl1.col1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t3.a::text;
&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; Nested Loop (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;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;10&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;Join&lt;/span&gt; Filter: ((lzl1.col1)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (t3.a)::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; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t3 (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;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;01&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl1 (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;1&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;10&lt;/span&gt; width&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;驱动表（图中outer，plan中的第一行表）将自身的每个行与被驱动表（图中inner，plan中第二行表）的每行匹配，驱动表只扫描一次，被驱动表被扫描N次（N=驱动表的行数）&lt;/p&gt;
&lt;p&gt;NL适用几乎所有场景，是最简单暴力的连接，一般较小的表为驱动表（其实两个表都不会太大，除非其他场景的join都不适用）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.2 Materialized Nested Loop Join&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2b45752abb3b.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;testdb&lt;span style="color:#f92672"&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; tbl_a &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; a, tbl_b &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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;Nested Loop (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;750230&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;5000&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;Join&lt;/span&gt; Filter: (a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; tbl_a a (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;145&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;10000&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; Materialize (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;98&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;5000&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; tbl_b b (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;73&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;5000&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果因为被驱动表（inner）需要被扫描多次，如果每次都是物理IO的话将会非常慢（看起来也很蠢）。Materialize就是把被驱动表scan到内存（work_mem）中，只做一次物理扫描表，让被驱动表在内存中被多次访问。&lt;/p&gt;
&lt;p&gt;这种场景是真实业务中非常常见的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.3 Indexed Nested Loop Join（inner indexed）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/661dba35e09a.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;testdb&lt;span style="color:#f92672"&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; tbl_c &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;, tbl_b &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; Nested Loop (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;1935&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;5000&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; tbl_b b (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;73&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;5000&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; tbl_c_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tbl_c &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; (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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;36&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.id)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;**1.4 NL变体 **&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d21a425177c0.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;本质都是NL，主要变化是两边的表上是否有用到索引、是否有Materialize&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.1 merge join&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9914756afd16.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;testdb&lt;span style="color:#f92672"&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; tbl_a &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; a, tbl_b &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.id &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; b.id &lt;span style="color:#f92672"&gt;&amp;lt;&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; Merge &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;944&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;71&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;984&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;71&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;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Merge Cond: (a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;809&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;834&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;10000&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; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: a.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; tbl_a a (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;145&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;10000&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; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;135&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;137&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;1000&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; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: b.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; tbl_b b (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;85&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;1000&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; Filter: (id &lt;span style="color:#f92672"&gt;&amp;lt;&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;(&lt;span style="color:#ae81ff"&gt;9&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;merge join的驱动表和被驱动表都需要先排序（plan中两表都有Sort）再匹配。优势在于表扫描次数、匹配次数比NL少，劣势在于需要排序。&lt;/p&gt;
&lt;p&gt;因为索引是排序的，再加上sql本身可能带distinct、group by、sort、max/min等等排序需求，所以merge join也常见&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2 Materialized Merge Join&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/fb637c9d769e.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;testdb&lt;span style="color:#f92672"&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; tbl_a &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; a, tbl_b &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; Merge &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;10466&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10578&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;58&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;5000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2064&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Merge Cond: (a.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6708&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;6733&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;10000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1032&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.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; tbl_a a (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;1529&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;10000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1032&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; Materialize (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3757&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3782&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;5000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1032&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;3757&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3770&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;19&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;5000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1032&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;: b.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; tbl_b b (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;1193&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;5000&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;9&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;Materialize虽然没有减少扫描表的次数（两个表都只有一次），不过排序操作可以放到backend的work_mem中进行，这样排序效率更高；当然如果超过work_mem会放到磁盘排序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.3 merge join变体&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7cfae9b6cfff.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;与NL变体类似，主要是Materialize和索引。用到索引的话，因为索引本身是有序的，所以就不需要额外的排序了。如下index scan不用排序也可以用到merge 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; 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; Merge &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;135&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;61&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;322&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;1000&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; Merge Cond: (&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; b.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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; tbl_c_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tbl_c &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; (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;318&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;10000&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; Sort (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;135&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;137&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;1000&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; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: b.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; tbl_b b (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;85&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;1000&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; Filter: (id &lt;span style="color:#f92672"&gt;&amp;lt;&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;(&lt;span style="color:#ae81ff"&gt;7&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;所以索引和Materialize在merge join中是很常见的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1 hash join&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


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


&lt;img src="https://lastdba.com/img/csdn/fb09a2a553f8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;hash join分为build和probe阶段&lt;/p&gt;
&lt;p&gt;build阶段将驱动表（上图的inner，plan中的第二行！）放到work_mem中，在probe阶段通过对比hash值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hash join只有‘=’才有可能发生&lt;/li&gt;
&lt;li&gt;hash join占用内存，一般两张表都不会很大&lt;/li&gt;
&lt;li&gt;注意驱动表（hash构建表）是plan中的第二行，跟NL相反&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3.2 Hybrid Hash Join with Skew&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;没看太懂，看上去可以落盘，有时间来补&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/pgsql03/05/01.html" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/pgsql03/05/01.html&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;十六、各种索引的适用场景（HASH/GIN/BTREE/GIST/BLOOM/BRIN）
 &lt;div id="十六各种索引的适用场景hashginbtreegistbloombrin" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%81%e5%85%ad%e5%90%84%e7%a7%8d%e7%b4%a2%e5%bc%95%e7%9a%84%e9%80%82%e7%94%a8%e5%9c%ba%e6%99%afhashginbtreegistbloombrin" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;(1) BTREE&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f490c66d7714.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikibooks.org/wiki/PostgreSQL/Index_Btree" target="_blank" rel="noreferrer"&gt;https://en.wikibooks.org/wiki/PostgreSQL/Index_Btree&lt;/a&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:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;=&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:#f92672"&gt;&amp;gt;&lt;/span&gt;		 &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;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;LIKE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;foo%&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;有个meta节点指向root节点&lt;/li&gt;
&lt;li&gt;叶子节点访问复杂度 O(logN) ，N为行数&lt;/li&gt;
&lt;li&gt;本身排序，容易被ORDER BY，min/max，group by，merge joins等等使用&lt;/li&gt;
&lt;li&gt;默认索引类型，最为常见。在不同的数据库中结构都差不多，一般就是叶子节点结构有些区别（mysql二级索引叶子节点存储索引键和主键，再通过主键去访问聚簇索引；oracle索引叶子节点存储索引键和rowid；pg索引叶子节点存储索引键和tid）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;(2) HASH&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a7e8e0b28860.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://leopard.in.ua/2015/04/13/postgresql-indexes）&lt;/p&gt;
&lt;p&gt;索引数据转化为32位的hash值，存放于对应的hash bucket中，不同的hash值指向各自的数据行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复杂度 O(1)&lt;/li&gt;
&lt;li&gt;hash索引&amp;quot;&lt;strong&gt;只&lt;/strong&gt;&amp;ldquo;能用于&lt;code&gt;=&lt;/code&gt;条件&lt;/li&gt;
&lt;li&gt;key value比较大的时候，一般都比BTREE索引更小，并且不需要像btree那样顺序对比每个字符大小，效率更高。所以hash索引更适合key value比较大的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;(3) GIST&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GIST-generalized search tree 与BTEE类似，也是一种平衡树。GIST索引其实不是一种索引，而是包含许多索引策略的框架，R-TREE,RD-TREE。不同于BTREE使用&lt;code&gt;=&lt;/code&gt;,&lt;code&gt;&amp;gt;&lt;/code&gt;等这类操作符处理数字、字符型数据，GIST更擅长处理地理、文本、图片等等数据，地理数据相关操作符有：&lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt;计算距离，&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;是否在左边，&lt;code&gt;@&amp;gt;&lt;/code&gt;是否包含等等&lt;/p&gt;
&lt;p&gt;GIST擅长的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GIS数据处理（类似的数据处理也可以，比如&lt;a href="https://pic.huodongjia.com/ganhuodocs/2017-07-15/1500104265.79.pdf" target="_blank" rel="noreferrer"&gt;digoal-GIST索引提升IP范围查询效率&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;邻近算法（pg_vector等向量数据涉及，空了研究~）&lt;/li&gt;
&lt;li&gt;full-text search（好像需要Contrib/intarray）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RTREE：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f63754993caa.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://en.wikipedia.org/wiki/R-tree）&lt;/p&gt;
&lt;p&gt;GIS数据最常见的索引就是RTREE。二维空间数据是一个个坐标，一个个扫描坐标去寻找地址是比较慢的，BTREE不适合索引此类数据，而RTREE应运而生。RTREE的核心是在不同层级上把邻近的点通过长方形(rectangle)进行分组，分组越细定位越准。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/4175817" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/4175817&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(4)SP-GIST：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Space-Partitioned GIST与GIST类似，也是一个创建索引的框架。SP-GIST适合将空间划分为非交叉区域的结构（注意RTREE是交叉的），例如quadtrees, k-d trees, and radix trees&lt;/p&gt;
&lt;p&gt;quadtrees：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2103e76b673a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://en.wikipedia.org/wiki/Quadtree）&lt;/p&gt;
&lt;p&gt;Q-TREE有正方形、长方形、各种形，最“正”的Q-TREE如上。Q-tree一般有如下性质：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个内部节点都有四个子节点&lt;/li&gt;
&lt;li&gt;索引遵循深度结构来寻找数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;k-d trees：&lt;/p&gt;
&lt;p&gt;


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


&lt;img src="https://lastdba.com/img/csdn/05d79891bd23.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://en.wikipedia.org/wiki/K-d_tree）&lt;/p&gt;
&lt;p&gt;k-dimensional tree以多维空间的概念来管理多维点，每个非叶节点都被一分为二。例如上面的立体空间图，是一个3维 k-d tree模型，第一次分割（红色）将整个空间一分为二，第二次分割（绿色）将子空间一分为二···直到不能分割。第二个图是3维 k-d tree的树形结构（不要把它看成是btree！），该树中只有3个维度：Name、Age、Salary&lt;/p&gt;
&lt;p&gt;radix-tree：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/157f00ff6b48.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://en.wikipedia.org/wiki/Radix_tree）&lt;/p&gt;
&lt;p&gt;radix（基数），每个child都合成其parent。找到key的复杂度为O(路径长度)，如果有common prefix，复杂度较高。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/4220639" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/4220639&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(5) GIN&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BRTEE和GIST在有非常多键值数据的情况下，查询效率非常低。而GIN索引（Generalized Inverted Index）非常擅长此类场景：array、full text、json的检索操作。另外，GIST和GIN都是Generalized生成式的，支持多种数据索引，同时他俩也支持full text索引。GIN只支持Bitmap scans。&lt;/p&gt;
&lt;p&gt;postgres原生支持许多操作符，其中有些是GIN索引相关的数据类型操作符：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/16/functions-array.html" target="_blank" rel="noreferrer"&gt;array的操作符&lt;/a&gt;，例如：&lt;code&gt;@&amp;gt;&lt;/code&gt; 数组1是否包含数组2；&lt;code&gt;unnest&lt;/code&gt; 展开数组&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/16/functions-textsearch.html" target="_blank" rel="noreferrer"&gt;全文搜索的操作符&lt;/a&gt;，例如：&lt;code&gt;@@&lt;/code&gt; tsvector是否匹配tsquery&lt;/li&gt;
&lt;li&gt;还有一些&lt;a href="https://www.postgresql.org/docs/16/functions-json.html" target="_blank" rel="noreferrer"&gt;json操作符&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG支持&lt;a href="https://www.postgresql.org/docs/16/datatype-textsearch.html" target="_blank" rel="noreferrer"&gt;两种数据类型以支持全文搜索&lt;/a&gt;：tsvector和tsquery&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1.tsvector&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;tsvector将text进行分词并&lt;strong&gt;去重和排序&lt;/strong&gt;，并使用tsvector_ops的操作符。例如如下分词&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;::tsvector;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tsvector 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&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;#39;Fat&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Rat&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;The&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;is&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;通过::tsvector分词一般不是分词的最终形态，to_tsvector函数用于分词的normalization（最终形态），它可以分词并展示分词的位置：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; to_tsvector(&lt;span style="color:#e6db74"&gt;&amp;#39;english&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to_tsvector 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&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;#39;fat&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;rat&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3&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;p&gt;注意&amp;rsquo;the&amp;rsquo;、&amp;lsquo;is&amp;rsquo;、&amp;lsquo;a&amp;rsquo;，大小写 都没有了，这是to_tsvector的规则，这种规则是符合真实场景的，因为全文搜索一般都是词汇&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2.tsquery&lt;/em&gt;：&lt;/p&gt;
&lt;p&gt;正常来说可以通过词汇来搜索tsvector分词过的text，如下&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; to_tsvector(&lt;span style="color:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;@@&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;rat&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;?&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;column&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; t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时如果要搜索“既包含fat又包含rat”，简单的词汇输入是办不到的，tsquery就是操作&lt;em&gt;用来搜索的分词的&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;tsquery可以由 &lt;code&gt;&amp;amp;&lt;/code&gt; (AND), &lt;code&gt;|&lt;/code&gt; (OR), &lt;code&gt;!&lt;/code&gt; (NOT), &lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt; (FOLLOWED 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; to_tsvector(&lt;span style="color:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;@@&lt;/span&gt; to_tsquery( &lt;span style="color:#e6db74"&gt;&amp;#39;fat&amp;amp;rat&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;?&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;column&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; t
&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; to_tsvector(&lt;span style="color:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;@@&lt;/span&gt; to_tsquery( &lt;span style="color:#e6db74"&gt;&amp;#39;fat&amp;amp;rat&amp;amp;cat&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;?&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;column&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; f
&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; to_tsvector(&lt;span style="color:#e6db74"&gt;&amp;#39;The Fat Rat is a Rat&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;@@&lt;/span&gt; to_tsquery( &lt;span style="color:#e6db74"&gt;&amp;#39;rat&amp;lt;-&amp;gt;fat&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;?&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;column&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; 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;fulltext gin：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;全文gin索引首先将索引字段分词（to_tsvector），类似如下doc_tsv就是将left分词后的状态：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; doc_tsv 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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; Can a sheet slitter &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slitter&amp;#39;&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:#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; How many sheets coul &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;could&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;mani&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slitter&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;7&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; I slit a sheet, a sh &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2&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:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Upon a slitted sheet &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;upon&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 style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Whoever slit the she &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;good&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&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:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slitter&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;whoever&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 style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; I am a sheet slitter &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slitter&amp;#39;&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; (&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; I slit sheets. &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&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:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; I am the sleekest sh &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ever&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sleekest&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slitter&amp;#39;&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:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; She slits the sheet &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sheet&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sit&amp;#39;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;slit&amp;#39;&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;然后通过分词和分词所在的ctid进行索引：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/815fee8ad284.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://postgrespro.com/blog/pgsql/4261647" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/4261647&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;索引以分词的顺序排序，类似BTREE；在叶节点存储分词所指向的ctid，以为同一分词可以来自多个tuple，所以分词可以指向多个ctid，如果有多个ctid需要构建posting tree，类似于其下的ctids再构建btree。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;fulltext gin寻址：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;for &amp;ldquo;mani&amp;rdquo; — (0,2).
for &amp;ldquo;slitter&amp;rdquo; — (0,1), (0,2), (1,2), (1,3), (2,2).&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/49ae172a7923.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GIN的更新：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果需要更新（增删改）一条文本，一般需要更新GIN索引上的很多地方，因为&lt;/p&gt;
&lt;p&gt;1)一条文本可以有很多分词，分散在GIN索引的各个branch上&lt;/p&gt;
&lt;p&gt;2)一个分词下面可能包含多个ctid，因为许多文本都有这个分词&lt;/p&gt;
&lt;p&gt;这就导致GIN的更新代价是非常大的。通常可以通过批量更新来执行，而不是一条一条的更新，因为有些分词是相同的，这样更新工作会少很多。&lt;/p&gt;
&lt;p&gt;除了批量更新外，GIN还提供了快速更新功能（fastupdate = true）：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/891a4e0ed575.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.pgcon.org/2016/schedule/attachments/434_Index-internals-PGCon2016.pdf）&lt;/p&gt;
&lt;p&gt;GIN的快速更新：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增量更新的数据会放到单独的地方，不排序&lt;/li&gt;
&lt;li&gt;当有vacuum或list到达gin_pending_list_limit时，会将增量更新回写到GIN主索引上&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;GiST or GIN?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GiST和GIN都是生成式的，是索引框架，同时都支持全文索引，但是他们的全文索引结构完全不同。GIST适合处理地理数据、多维空间数据，，GIN主要是对键值包含多value的场景进行索引，如array、full text、json。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GIN索引比GiST更快，一般而言全文索引可以盲选GIN（ 参考 &lt;a href="https://leopard.in.ua/2015/04/13/postgresql-indexes" target="_blank" rel="noreferrer"&gt;GIST vs GIN&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;只有在非常多更新的情况下，可以考虑GiST索引。前提是fast update策略无法解决更新问题（如配置夜间回写策略），最好对GiST和GIN的全文索引的各种场景进行对比。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/datatype-textsearch.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/datatype-textsearch.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/4261647" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/4261647&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(6) BRIN&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0ee340aa3ea8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://postgrespro.com/blog/pgsql/5967830）&lt;/p&gt;
&lt;p&gt;BRIN不是tree类型的索引，数据以多个page（or Block）为一个range（类似range partition，但是不物理分区），表被分为一个个的range，就像这个索引的名字一样Block Range Index（BRIN）。&lt;/p&gt;
&lt;p&gt;BRIN索引最关键的就是revmap层，revmap只存储键值的范围和ctid，&lt;strong&gt;而不存储键值本身&lt;/strong&gt;。这也是为什么BRIN索引非常小的原因，存储键值的话就类似没有branch的BTREE索引了。&lt;/p&gt;
&lt;p&gt;因为只存储键值的范围和ctid，这样导致在寻找数据的时候，需要访问命中的revmap页上所指向的所有数据页，最后再recheck出最终数据行。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;															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; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; flights_bi (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;75&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;151&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;192&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;210&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;587353&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:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: (airport_utc_offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;08:00:00&amp;#39;&lt;/span&gt;::interval)
&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Recheck&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;191318&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Heap Blocks: lossy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;13380&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 &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; flights_bi_airport_utc_offset_idx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;74&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;74&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;999&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;133800&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (airport_utc_offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;08:00:00&amp;#39;&lt;/span&gt;::interval)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;索引键值的顺序和存储顺序是否一致是非常关键的。例如，一个额外的键值数据不是顺序存储的，它可能在“距离”较远的页上，此时必须多一个IO来访问远距离的数据页。最糟糕的情况，可能导致扫描整个表：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/46ee8f7372ff.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.pgcon.org/2016/schedule/attachments/434_Index-internals-PGCon2016.pdf）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BRIN适合的场景：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BRIN索引只适合索引键值与存储顺序高度一致的数据。可以直接查pg_stats中的列的correlation，应趋近于1（-1似乎也符合？），一般是递增主键和时间字段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;几乎没有更新的场景。更新可能导致correlation降低&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BRIN索引一般适合极大的数据，特别是TB及以上的数据&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/5967830" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/5967830&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(7) Rum&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rum是一个extension，没有原生包含在PG里。RUM和GIN索引是类似的，区别在于RUM多存储了tsvector的位置信息。&lt;/p&gt;
&lt;p&gt;GIN虽然需要to_tsvector()（或者直接tsvector）来分词，但是GIN没有使用到to_tsvector()分词出来的位置信息。例如，如果要想找两个分词的距离，GIN索引是无法实现的，只能通过to_tsvector()分词出来的裸数据来判断。此时RUM就可以派上用场了。&lt;/p&gt;
&lt;p&gt;RUM索引相对于GIN，在ctid旁边附带了分词的位置信息：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9c5cdfb1d385.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://postgrespro.com/blog/pgsql/4262305）&lt;/p&gt;
&lt;p&gt;RUM与GIN类似适用于全文索引，额外的还有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以用距离操作符（如&amp;lt;=&amp;gt;）计算距离&lt;/li&gt;
&lt;li&gt;可以通过位置来排序&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/4262305" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/4262305&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(8)BLOOM&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BLOOM过滤器可以快速确认一个元素是否在一个子集中。布隆过滤器可能出现假阳性，在子集中不一定是真的，不在子集中一定是真的。BLOOM索引也不是tree结果，跟BRIN类似也是平展的（与BRIN类似也要recheck）。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/bf06b10cd015.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://en.wikipedia.org/wiki/Bloom_filter）&lt;/p&gt;
&lt;p&gt;bloom索引可以索引很多列，bloom索引与hash索引有些类似，与hash索引不同的是它可以指定hash的字段并组合到一起，汇总后的长度受length限制。正因为它分段hash并截断的特性，所以存在假阳性。length越短，假阳性的可能性越大（length最大4096 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-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; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; ... &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; bloom(...) &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;length&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;..., col1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;..., col2&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;img src="https://lastdba.com/img/csdn/93a3ccefbd2d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://postgrespro.com/blog/pgsql/5967832）&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/bloom.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/current/bloom.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/5967832" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/5967832&lt;/a&gt;&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;index type&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;/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;btree&lt;/td&gt;
 &lt;td&gt;btree；branch存储键值范围，页节点存储键值和ctid，一般是升序&lt;/td&gt;
 &lt;td&gt;&amp;gt;=,=,is null等常见操作符都支持，最左匹配原则&lt;/td&gt;
 &lt;td&gt;O(logN)&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;键值大时索引会非常大；索引碎片，分裂(HOT会减缓该现象）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;hash&lt;/td&gt;
 &lt;td&gt;构建hash桶，不同hash值指向不同的数据行&lt;/td&gt;
 &lt;td&gt;仅=&lt;/td&gt;
 &lt;td&gt;O(1)&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;仅有=条件的场景；key value较大&lt;/td&gt;
 &lt;td&gt;一般比较小；寻址快&lt;/td&gt;
 &lt;td&gt;场景极少&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GiST&lt;/td&gt;
 &lt;td&gt;索引框架；R-TREE,RD-TREE；在不同图层上对地址进行分组，分组越细定位越准&lt;/td&gt;
 &lt;td&gt;空间操作符：如&lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt;计算距离，&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;是否在左边，&lt;code&gt;@&amp;gt;&lt;/code&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;GIS；KNN；频繁更新的全文索引&lt;/td&gt;
 &lt;td&gt;GIS，多维度的数据&lt;/td&gt;
 &lt;td&gt;特殊场景&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sp-GiST/Q-tree&lt;/td&gt;
 &lt;td&gt;（sp-GiST是索引框架；索引不包含重叠数据) Q-tree:每个节点都有4个年内部节点;&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;GIS&lt;/td&gt;
 &lt;td&gt;GIS&lt;/td&gt;
 &lt;td&gt;GIS&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sp-GiST/k-d tree&lt;/td&gt;
 &lt;td&gt;k-d tree:将多维空间在节点上一分为二，直到不能再分割;&lt;/td&gt;
 &lt;td&gt;空间操作符&lt;/td&gt;
 &lt;td&gt;最低O(k)，平均O(logN)，最高O(N/2)&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;GIS；多维数据&lt;/td&gt;
 &lt;td&gt;GIS，多维度的数据&lt;/td&gt;
 &lt;td&gt;特殊场景&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sp-GiST/radix-tree&lt;/td&gt;
 &lt;td&gt;3.radix-tree:每个child都合成其parent；&lt;/td&gt;
 &lt;td&gt;一般操作符；=,&amp;gt;,~等&lt;/td&gt;
 &lt;td&gt;最低O(1),最高O(N)&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;没有common数据的场景&lt;/td&gt;
 &lt;td&gt;比一般的GiST支持一般操作符&lt;/td&gt;
 &lt;td&gt;场景少，可能会非常慢&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GIN&lt;/td&gt;
 &lt;td&gt;索引框架;类似btree结构，branch存储分词范围，leaf存储分词和指向的ctid，一个分词指向多个ctid可能有子post tree结构；fast update打开的情况下多一个存储增量数据的链表空间&lt;/td&gt;
 &lt;td&gt;不同数据类型操作符稍有不同，一般有 @@含有&lt;/td&gt;
 &lt;td&gt;与文本长度、分词重复度相关，近似O(logN)&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;N（索引branch有序，但索引没有分词位置信息）&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;键值包含多value的场景，如array;full text;json;很多列&lt;/td&gt;
 &lt;td&gt;键值包含多value的场景可能是最佳选择&lt;/td&gt;
 &lt;td&gt;更新需要合适的策略&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;BRIN&lt;/td&gt;
 &lt;td&gt;非tree结构，将数据页以range分开，rev索引层只键值存储范围和ctid&lt;/td&gt;
 &lt;td&gt;一般操作符：&amp;lt; &amp;lt;= = &amp;gt;= &amp;gt;&lt;/td&gt;
 &lt;td&gt;找到数据页的复杂度O(1)，返回数据复杂度O(N），N为recheck的行数&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;极度要求corrlation&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;RUM&lt;/td&gt;
 &lt;td&gt;与GIN类似，仅多存储分词位置信息&lt;/td&gt;
 &lt;td&gt;包含GIN的操作符，多一些位置操作符&lt;/td&gt;
 &lt;td&gt;与文本长度、分词重复度相关，近似O(logN)&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;有（可用于邻近查找）&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;键值包含多value的场景，适合KNN&lt;/td&gt;
 &lt;td&gt;比GIN多存储位置信息&lt;/td&gt;
 &lt;td&gt;需要安装额外插件&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;BLOOM&lt;/td&gt;
 &lt;td&gt;每个字段hash并截断，非树形结构，以位图过滤&lt;/td&gt;
 &lt;td&gt;一般操作符：&amp;lt; &amp;lt;= = &amp;gt;= &amp;gt;&lt;/td&gt;
 &lt;td&gt;未命中时O(1)，命中时O(N)，N为recheck的行数&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;recheck时可能很慢&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;索引小节的其他参考：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://it.badykov.com/blog/2020/03/21/postgresql-indexes/" target="_blank" rel="noreferrer"&gt;Types of PostgreSQL Indexes. Short and clear&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://leopard.in.ua/2015/04/13/postgresql-indexes" target="_blank" rel="noreferrer"&gt;https://leopard.in.ua/2015/04/13/postgresql-indexes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pic.huodongjia.com/ganhuodocs/2017-07-15/1500104265.79.pdf" target="_blank" rel="noreferrer"&gt;https://pic.huodongjia.com/ganhuodocs/2017-07-15/1500104265.79.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.aliyun.com/article/698090?spm=a2c6h.12873639.article-detail.43.702e7149IBMYL9" target="_blank" rel="noreferrer"&gt;https://developer.aliyun.com/article/698090?spm=a2c6h.12873639.article-detail.43.702e7149IBMYL9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgresql.us/events/pgopen2019/sessions/session/647/slides/45/look-it-up.pdf" target="_blank" rel="noreferrer"&gt;https://postgresql.us/events/pgopen2019/sessions/session/647/slides/45/look-it-up.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pgcon.org/2016/schedule/attachments/434_Index-internals-PGCon2016.pdf" target="_blank" rel="noreferrer"&gt;https://www.pgcon.org/2016/schedule/attachments/434_Index-internals-PGCon2016.pdf&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%8d%81%e4%b8%83%e8%a1%8c%e9%94%81%e6%98%af%e5%a6%82%e4%bd%95%e5%ae%9e%e7%8e%b0%e7%9a%84%e8%a1%8c%e9%94%81%e6%98%af%e5%90%a6%e4%bc%9a%e5%ad%98%e5%82%a8%e5%9c%a8%e5%85%b1%e4%ba%ab%e5%86%85%e5%ad%98%e4%b8%ad" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PG中的行锁在行的行头，不会在内存中实现。&lt;/p&gt;
&lt;p&gt;(1)t1更新后不提交，会获得relation和transactionid的排他锁：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/16040258a95a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(2)t2更新同一行会被阻塞，本次阻塞通过transactionid的sharelock锁实现，relation、tuple锁 T2都会获得：&lt;/p&gt;
&lt;p&gt;


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


&lt;img src="https://lastdba.com/img/csdn/d3b2e8a88a88.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;(3)t3再更新这个行，本次阻塞通过tuple排他锁实现&lt;/p&gt;
&lt;p&gt;


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


&lt;img src="https://lastdba.com/img/csdn/b5ea7c9fe3f1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;总之，&lt;strong&gt;PG的行锁通过transactionid锁、relation锁和tuple锁共同实现：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5160903bb82b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;《postgresql-internals-14》&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/5968005" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/5968005&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%8d%81%e5%85%ab%e6%b5%81%e5%a4%8d%e5%88%b6%e5%92%8c%e9%80%bb%e8%be%91%e5%a4%8d%e5%88%b6%e7%9a%84%e5%8c%ba%e5%88%ab%e4%bb%a5%e5%8f%8a%e5%90%84%e8%87%aa%e9%80%82%e7%94%a8%e7%9a%84%e5%9c%ba%e6%99%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这里的流复制一般指的是PG的物理复制，通过全量的WAL日志同步到下游，由下游的PG库回放wal，是物理块级别的复制：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d8149234af0e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;逻辑复制需要逻辑解析wal上相关表的事务信息，通过reorder buffer排序事务，然后由output plugin决定数据输出形式，下游不一定是PG库。必须有复制槽管理逻辑解析、output plugin、reorder buffer、复制点位等信息，还有replica identity、slot/sender状态信息等知识点：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2fde90f69b14.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;逻辑复制本身存在很多问题，然而应用越来越广泛，是PG社区重点更新的功能之一。&lt;/p&gt;
&lt;p&gt;例如（不完全统计）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;logical_decoding_work_mem不是写死的4096（条变更），成为GUI参数可调整。解析的落盘的问题得到一定缓解&lt;/li&gt;
&lt;li&gt;在PG14后支持流式逻辑复制，事务没有提交也可以传递数据到下游，后续的事务提交信息决定是否应用该变更事务&lt;/li&gt;
&lt;li&gt;从库支持复制槽，逻辑复制可建立在从库上&lt;/li&gt;
&lt;li&gt;failover slot（进行中？）&lt;/li&gt;
&lt;li&gt;还有很多很多更新···&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/120000817?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170744169916800184170543%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170744169916800184170543&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-120000817-null-null.nonecase&amp;amp;utm_term=%E6%B5%81%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PG流复制详解&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170744169916800184170543%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170744169916800184170543&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-2-129291207-null-null.nonecase&amp;amp;utm_term=%E6%B5%81%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg内功修炼：逻辑复制&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%8d%81%e4%b9%9d%e6%b5%81%e5%a4%8d%e5%88%b6%e5%86%b2%e7%aa%81%e6%98%af%e4%bb%80%e4%b9%88%e4%bb%a5%e5%8f%8a%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e4%ba%a7%e7%94%9f%e5%a4%8d%e5%88%b6%e5%86%b2%e7%aa%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;产生冲突的原因：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;备库正在执行基于某个表的查询（这个查询可能是应用产生的，也可能是手动连接进行的查询），这时主库执行了drop table操作，该操作写入wal日志后传至备库进行应用，为了保证数据一致性，postgresql必然会迅速回放数据，这时drop table和select就会形成冲突。因为主库不知道从库的事务状态，而从库又需要与主库保持一致，所以才发生了“查询冲突”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;产生冲突的场景：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.主库排他锁（包括显示LOCK命令和各种DDL）
2.主库vacuum清理死元组，从库如果正在使用该元组，就会产生冲突
3.主库删除了从库查询正在使用的表空间
4.主库删除了从库正在使用的数据库&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缓解查询冲突（无法彻底解决）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hot_standby_feedback&lt;/code&gt;：备库会定期向主库通知最小活跃事务id（xmin）值，这样使得主库vacuum进程不会清理大于xmin值的事务。&lt;/p&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_archive_delay&lt;/code&gt;：备机因为处理归档的wal日志产生查询冲突而取消查询之前的等待时间&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vacuum_defer_cleanup_age&lt;/code&gt;：指定vacuum延迟清理死亡元组的事务数，即vacuum和vacuum full操作不会立即清理刚刚被删除元组&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/120000817?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170744169916800184170543%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170744169916800184170543&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-120000817-null-null.nonecase&amp;amp;utm_term=%E6%B5%81%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PG流复制详解&lt;/a&gt;&lt;/p&gt;

&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="#%e4%ba%8c%e5%8d%81%e7%ae%80%e8%bf%b0-postgresql-%e4%b8%ad%e7%9a%84%e6%9d%83%e9%99%90%e4%bd%93%e7%b3%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b45d38154897.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;不知道怎么汇总，汇总下来应该也记不住，属实有些复杂，简单几点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权限访问需要每层都“打通”，缺一不可&lt;/li&gt;
&lt;li&gt;最好将只读/读写/owner用户区分开&lt;/li&gt;
&lt;li&gt;只读、读写权限可通过角色来管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/jQP36rXZb4sgA71AaIJ-Sw" target="_blank" rel="noreferrer"&gt; PostgreSQL学徒:又被权限搞晕了？拿捏！&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="#%e4%ba%8c%e5%8d%81%e4%b8%80%e5%b8%b8%e8%a7%81%e7%9a%84%e9%ab%98%e5%8f%af%e7%94%a8%e6%96%b9%e6%a1%88%e4%bb%a5%e5%8f%8a%e9%ab%98%e5%8f%af%e7%94%a8%e9%80%89%e5%9e%8b%e5%8f%8a%e4%bc%98%e7%bc%ba%e7%82%b9" 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;switch over、failover&lt;/li&gt;
&lt;li&gt;负载均衡、读写分离&lt;/li&gt;
&lt;li&gt;主机、数据库、业务层面的高可用&lt;/li&gt;
&lt;li&gt;VIP切换、连接串高可用、如何切换连接&lt;/li&gt;
&lt;li&gt;如何解决单点故障或脑裂问题，如何选举&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面介绍一些网上能找到的架构：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pgpool-II+watchdog&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/748bd7fc3712.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.pgpool.net/docs/latest/en/html/example-cluster.html）&lt;/p&gt;
&lt;p&gt;优点：自动故障转移、读写分离、负载均衡、watchdog选举&lt;/p&gt;
&lt;p&gt;缺点：配置复杂、pgpool不完全支持所有pg特性、pgpool有性能丢失问题、依赖watchdog选举&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;patroni+etcd&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/ed1ce367a7b8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;优点：图形界面（patroni）、自动故障转移、多数派选举&lt;/p&gt;
&lt;p&gt;缺点：学习成本、不支持其他数据库（patroni）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;partroni+pgbouncer+haproxy+etcd&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e7604c9266a6.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.percona.com/sites/default/files/eBook-PostgreSQL-High-Availability.pdf）&lt;/p&gt;
&lt;p&gt;优点：主打一个开源节流：haproxy用于负载均衡，pgcbouncer管理连接池、patroni管理集群、etcd用于选举&lt;/p&gt;
&lt;p&gt;缺点：配置非常复杂&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;平安金融云rasesql架构&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/78b4331a5822.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.ocftcloud.com/ssr/help/database/RASESQL/intro.Architecture）&lt;/p&gt;
&lt;p&gt;优点：支持故障转移、架构简单&lt;/p&gt;
&lt;p&gt;缺点：同城远程不可直接只读访问，资源占用较多，不可选举（？）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;阿里云polar-x&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


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


&lt;img src="https://lastdba.com/img/csdn/3578c8002447.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（&lt;a href="https://ucc-private-download.oss-cn-beijing.aliyuncs.com/ab3f233b4a4c405986b2a8196cb53b47.pdf?Expires=1708410598&amp;amp;OSSAccessKeyId=LTAIvsP3ECkg4Nm9&amp;amp;Signature=O9UIudjtFyMmQW4eZf2BlClhVDk%3D" target="_blank" rel="noreferrer"&gt;PolarDB for PostgreSQL 三节点功能介绍&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;优点：读写分离、可以加入不参加选举的节点、故障转移、logger节点参与选举/数据流/备份&lt;/p&gt;
&lt;p&gt;缺点：&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;google cloud pg&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;有三种架构可以选择：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b85525616eeb.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;google云原生架构（MIG）：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0cc376b9b922.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;优点：三种方案可以选择、文档完善！（其他两个方案都源自开源架构，优缺点都差不多，下面介绍下MIG云原生方案）&lt;/p&gt;
&lt;p&gt;MIG方案优势：不依赖PG原生的高可用方案，通过Regional persistent disk来实现数据高可用，主zone网络隔离，可把disk attach到同一region的zoneB上使用（1分钟内完成attach）。&lt;/p&gt;
&lt;p&gt;MIG方案缺点：没有只读库、只能同region内故障转移（不支持搭建在多region上）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;aurora for pg&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/6c3c996ceeb5.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;优点：架构简单，恢复后的主节点可自动加入集群，多region部署，standby可读&lt;/p&gt;
&lt;p&gt;缺点：（似乎）没有选举动作，文档文字多图少&lt;/p&gt;
&lt;p&gt;崔健：PostgreSQL的高可以架构设计与实践&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pgpool.net/docs/latest/en/html/example-cluster.html" target="_blank" rel="noreferrer"&gt;https://www.pgpool.net/docs/latest/en/html/example-cluster.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.postgres.cn/downfiles/pgconf_2018/PostgresChina2018_%E6%B1%AA%E6%B4%8B_PG%E4%B9%8B%E9%AB%98%E5%8F%AF%E7%94%A8%E7%89%B9%E6%80%A7%E3%80%81%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.pdf" target="_blank" rel="noreferrer"&gt;汪总： Postgresql 高可用&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cloud.tencent.com/developer/article/1185379" target="_blank" rel="noreferrer"&gt;使用Patroni和HAProxy创建高度可用的PostgreSQL集群&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.percona.com/sites/default/files/eBook-PostgreSQL-High-Availability.pdf" target="_blank" rel="noreferrer"&gt;https://www.percona.com/sites/default/files/eBook-PostgreSQL-High-Availability.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ucc-private-download.oss-cn-beijing.aliyuncs.com/ab3f233b4a4c405986b2a8196cb53b47.pdf?Expires=1708410598&amp;amp;OSSAccessKeyId=LTAIvsP3ECkg4Nm9&amp;amp;Signature=O9UIudjtFyMmQW4eZf2BlClhVDk%3D" target="_blank" rel="noreferrer"&gt;PolarDB for PostgreSQL 三节点功能介绍&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cloud.google.com/architecture/architectures-high-availability-postgresql-clusters-compute-engine" target="_blank" rel="noreferrer"&gt;https://cloud.google.com/architecture/architectures-high-availability-postgresql-clusters-compute-engine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.html" target="_blank" rel="noreferrer"&gt;https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.html&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;二十二、synchronous_commit 五种级别的区别，为什么备库的查询不能立马看到主库插入的数据
 &lt;div id="二十二synchronous_commit-五种级别的区别为什么备库的查询不能立马看到主库插入的数据" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%e5%8d%81%e4%ba%8csynchronous_commit-%e4%ba%94%e7%a7%8d%e7%ba%a7%e5%88%ab%e7%9a%84%e5%8c%ba%e5%88%ab%e4%b8%ba%e4%bb%80%e4%b9%88%e5%a4%87%e5%ba%93%e7%9a%84%e6%9f%a5%e8%af%a2%e4%b8%8d%e8%83%bd%e7%ab%8b%e9%a9%ac%e7%9c%8b%e5%88%b0%e4%b8%bb%e5%ba%93%e6%8f%92%e5%85%a5%e7%9a%84%e6%95%b0%e6%8d%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f2ec64d6d8a4.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/120000817?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170744169916800184170543%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170744169916800184170543&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-120000817-null-null.nonecase&amp;amp;utm_term=%E6%B5%81%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PG流复制详解&lt;/a&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%8c%e5%8d%81%e4%b8%89%e4%ba%8b%e5%8a%a1-id-%e5%9b%9e%e5%8d%b7%e7%9a%84%e5%8e%9f%e5%9b%a0%e4%bb%a5%e5%8f%8a%e5%a6%82%e4%bd%95%e7%bb%b4%e6%8a%a4%e4%bc%98%e5%8c%96" 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，虚拟事务ID是本地计数的，虽然有回卷问题，但是会话重启VXID重新计数，所以基本没有什么问题。&lt;/p&gt;
&lt;p&gt;但是事务ID是有上限的，&lt;code&gt;TransactionId&lt;/code&gt;是32位无符号整型，总共可以存储 &lt;code&gt;2^32=4294967296&lt;/code&gt;，42亿多个事务，此时需要把事务ID回卷到初始状态，这就是为什么事务ID是一个环。&lt;/p&gt;
&lt;p&gt;由于可见性原则，又需要把42亿事务分成两半，一半代表未来一半代表过去，PG实例中的最大最小事务之差不能超过21亿，这就是21亿事务的由来。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/bbce62f757b4.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.interdb.jp/pg/pgsql05/01.html）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;事务ID冻结：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于可见性元组，例如一个可见的行（如下xid=100）与最新的事务之差超过了21亿，它会由可见变为不可见：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/57a0de81e82c.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（忘了哪来的图了，自己找找）&lt;/p&gt;
&lt;p&gt;为了解决这个问题引进事务ID冻结机制。事务ID冻结将过旧的元组的xmin设置为FrozenXID=2，比所有正常事务都旧。也就是说txid=2对于所有正常事务(txid&amp;gt;=3)都是可见的。在9.4及以后的版本，用t_infomask中的xmin_frozen来表示冻结元组，而不是重写t_xmin为2。&lt;/p&gt;
&lt;p&gt;**惰性模式：**vm文件最初是为了减少vacuum的消耗，它可以让vacuum跳过完全没有死元组的页（all-visible ）。后来（pg9.4）增强了freeze进程，让惰性模式冻结操作也可以在vacuum过程中跳过这些完全没有死元组的页（all-visible）。&lt;/p&gt;
&lt;p&gt;惰性模式的冻结触发条件：随vacuum操作触发（似乎没有自己的触发条件？？？）&lt;/p&gt;
&lt;p&gt;惰性模式冻结哪些元组：除开标记在vm中all-visible跳过的页，冻结那些元组的xmin和活跃事务ID（实际上是oldestxmin）的间隔超过&lt;code&gt;vacuum_freeze_min_age&lt;/code&gt;（默认5kw）的元组，将其标记为xmin_frozen状态。如下图中tuple 9的xmin=3000不会冻结。&lt;/p&gt;
&lt;p&gt;惰性模式更像是vacuum过程中附带的操作：反正都在concurrently vacuum扫描和清理死元组，pages已经扫描了，顺带把能frozen的元组frozen了。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/47912e7b0750.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;**急性模式：**惰性模式有个问题，它随vacuum一起工作，会跳过vm中完全没有死元组的页（all-visible），如果一个页中的元组全是活元组（all-visible but not all-frozen ）且xmin都很旧了，只靠惰性模式是冻结不到的。所以冻结需要急性模式：跳过vm中已经标记的all-frozen页并冻结。在真实场景中，一般急性模式才是经常周期运行的且需要关注的：&lt;strong&gt;哪怕表中只有一个页的元组都是insert插入（哪怕只有一个静态页），就需要急性模式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;急性模式的冻结触发条件：&lt;/p&gt;
&lt;p&gt;1）针对vacuum操作的&lt;code&gt;Vacuum_freeze_table_age&lt;/code&gt;：当&lt;strong&gt;database级&lt;/strong&gt;的最小xmin（实际是&lt;code&gt;pg_database.datfrozenxid&lt;/code&gt;字段，也是该database上所有&lt;code&gt;pg_class.relfrozenxid&lt;/code&gt;的最小值）和活跃事务ID（实际上是oldestxmin）的间隔超过&lt;code&gt;Vacuum_freeze_table_age&lt;/code&gt;时（默认1.5亿），&lt;strong&gt;vacuum&lt;/strong&gt;会使用触发急性模式冻结。&lt;/p&gt;
&lt;p&gt;2）针对autovacuum的&lt;code&gt;autovacuum_freeze_max_age&lt;/code&gt;：无论是惰性模式还是急性模式的&lt;code&gt;Vacuum_freeze_table_age&lt;/code&gt;，都需要先触发vacuum操作，仅靠vacuum本身触发条件去做冻结是不靠谱的，需要一个针对freeze的deadline参数：&lt;code&gt;autovacuum_freeze_max_age&lt;/code&gt;。当元组年龄大于&lt;code&gt;autovacuum_freeze_max_age&lt;/code&gt;时(2亿），强制触发autovacuum去冻结元组。哪怕autovacuum是关闭的，仍然可以触发这个deadline条件的冻结操作。&lt;/p&gt;
&lt;p&gt;急性模式冻结哪些元组：与惰性模式类似，除了all-frozen页（惰性是all-visible，是有区别的），冻结那些元组的xmin和活跃事务ID（实际上是oldestxmin）的间隔超过&lt;code&gt;vacuum_freeze_min_age&lt;/code&gt;（默认5kw）的元组，如下tuple 11没有被frozen&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d24f548bb484.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vacuum freeze命令：&lt;/strong&gt;&lt;code&gt;vacuum freeze&lt;/code&gt;命令等价于把vacuum_freeze_min_age和vacuum_freeze_table_age设置为0，并且以急切模式进行冻结操作，冻结所有非活动的xmin元组。&lt;/p&gt;
&lt;p&gt;**vacuum_failsafe_age：**由于大表的vacuum操作非常慢，可能freeze操作还没跑完，事务ID已经回卷了。由于freeze是由vacuum进程做的，vacuum又有很多其他操作和参数设置，为了加速freeze，将cost-based vacuuming、buffer策略、index vacuuming都忽略。参数默认16亿，实际上vacuum过程中参数生效值不低于autovacuum_freeze_max_age*105%&lt;/p&gt;
&lt;p&gt;**clog可能也更新：**额外的，冻结如果更新了pg_database.datfrozenxid ，还会清理不需要的clog。clog是记录事务状态的，以判断“比较新“的事务和元组可见性。如果一个database中的frozenxid都推进的比较新了，说明那些”老的”元组都被标记为了frozen——一直可见，所以clog中“老的”事务状态信息可以不要了&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/1e864c9bc4a1.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;维护优化方案：&lt;/strong&gt;（汇总自灿总的汇总）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;生产环境中做好pg_database.frozenxid的监控，当快达到触发值时，我们应该选择一个业务低峰期窗口主动执行vacuum freeze操作，而不是等待数据库被动触发。&lt;/li&gt;
&lt;li&gt;分区表，表过大会造成prevent wraparound操作时间较长&lt;/li&gt;
&lt;li&gt;对大表设置不同的vacuum年龄，alter table test set (autovacuum_freeze_max_age=xxxx);&lt;/li&gt;
&lt;li&gt;用户自己调度 freeze，如在业务低谷的时间窗口，对年龄较大，数据量较大的表进行vacuum freeze。&lt;/li&gt;
&lt;li&gt;关注阻止freeze的场景：长事务、复制槽、hot_standby_feedback、pg_dump、游标、孤儿事情&lt;/li&gt;
&lt;li&gt;设置足够的worker进程，以免需要vacuum的场景全部排队&lt;/li&gt;
&lt;li&gt;如果关注负载问题，可以考虑开启cost-based vacuuming，让vacuum达到一定阈值时睡眠（vacuum_cost_delay等参数）&lt;/li&gt;
&lt;li&gt;autovacuum_freeze_max_age的值应大于vacuum_freeze_table_age，给手动vacuum留一定的空间，官方建议：vacuum_freeze_table_age = 0.95 * autovacuum_freeze_max_age；如果vacuum_freeze_table_age 低于0.95 * autovacuum_freeze_max_age，那么vacuum仍然取0.95 * autovacuum_freeze_max_age。&lt;/li&gt;
&lt;li&gt;vacuum_failsafe_age。pg14及以上设置合理的参数vacuum_failsafe_age，加速大表的freeze操作防止回卷，该参数应设置为大于autovacuum_freeze_max_age*105%&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://www.interdb.jp/pg/" target="_blank" rel="noreferrer"&gt;https://www.interdb.jp/pg/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/p6aFhghpDEGu6lIBD8A5Yw" target="_blank" rel="noreferrer"&gt;深入理解PostgreSQL冻结炸弹&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782577?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170744852416800182714289%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=170744852416800182714289&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-130782577-null-null.nonecase&amp;amp;utm_term=%E5%9B%9E%E5%8D%B7&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg事务：事务ID&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;二十四、vacuum / autovacuum 的作用以及如何调优
 &lt;div id="二十四vacuum--autovacuum-的作用以及如何调优" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%e5%8d%81%e5%9b%9bvacuum--autovacuum-%e7%9a%84%e4%bd%9c%e7%94%a8%e4%bb%a5%e5%8f%8a%e5%a6%82%e4%bd%95%e8%b0%83%e4%bc%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;清除UPDATE或DELETE操作后留下的“死元祖”&lt;/li&gt;
&lt;li&gt;跟踪表块中可用空间，更新free space map&lt;/li&gt;
&lt;li&gt;更新index-only扫描所需的visibility map&lt;/li&gt;
&lt;li&gt;“冻结”表中的行，防止事务ID回卷&lt;/li&gt;
&lt;li&gt;定期ANALYZE，更新统计信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;调优：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;设置足够的worker进程，以免需要vacuum的场景排队&lt;/li&gt;
&lt;li&gt;可增大maintenace_work_mem（或autovacuum_work_mem）的值&lt;/li&gt;
&lt;li&gt;关注阻止vacuum的场景：长事务、复制槽、hot_standby_feedback、pg_dump、游标、孤儿事情&lt;/li&gt;
&lt;li&gt;对于特殊表（业务敏感表和大表）可单独设置autovacuum触发阈值（threshold、fillfactor；insert threshold、fillfactor)：死元组回收阈值、统计信息更新阈值、防止回卷阈值&lt;/li&gt;
&lt;li&gt;对于特殊表（业务敏感表和大表）关闭表级的autovacuum，在业务低峰期运行vacuum，包括死元组回收、统计信息、回卷动作&lt;/li&gt;
&lt;li&gt;如果需要关注业务负载压力，可开启cost-based vacuuming，让vacuum达到某阈值时睡眠&lt;/li&gt;
&lt;li&gt;分区表，避免vacuum长时间运行不完，甚至刚运行完又立即vacuum&lt;/li&gt;
&lt;li&gt;尽量避免vacuum full 8级锁操作。用户逻辑复制+rename或者pg_repack处理表膨胀和索引膨胀，增加表/索引的执行效率并回收空间&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;二十五、函数三态以及函数为什么需要有 execute
 &lt;div id="二十五函数三态以及函数为什么需要有-execute" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%e5%8d%81%e4%ba%94%e5%87%bd%e6%95%b0%e4%b8%89%e6%80%81%e4%bb%a5%e5%8f%8a%e5%87%bd%e6%95%b0%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e6%9c%89-execute" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;volatile函数（不稳定，默认）&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;strong&gt;每个query执行时&lt;/strong&gt;获取一次snapshot，因此即便在同一函数中相同interactive query多次执行，每次的可见数据不同执行结果也会不同。&lt;/li&gt;
&lt;li&gt;由于每次要重新计算，优化器无法提前预估，其性能可能较差&lt;/li&gt;
&lt;li&gt;不支持创建函数索引&lt;/li&gt;
&lt;li&gt;典型函数：timeofday()、random()、所有修改类函数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;stable函数（稳定）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不可以修改数据库&lt;/li&gt;
&lt;li&gt;在同一个事务中，对于相同的参数，返回的结果相同。在函数开始执行时获取snapshot，内部的每个query不再重复获取，函数内的相同的interactive query执行结果是一致的。&lt;/li&gt;
&lt;li&gt;不支持创建函数索引&lt;/li&gt;
&lt;li&gt;典型函数：current_timestamp家族函数，在一个事务中无论调用多少次只会有一个值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;immutable函数（非常稳定）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不可以修改数据库&lt;/li&gt;
&lt;li&gt;只要给定相同参数，永远返回相同的结果。快照获取原理与stable函数一致。&lt;/li&gt;
&lt;li&gt;与stable函数的重要区别是：immutable不仅缓存plan，在后续的执行时直接使用这个plan&lt;/li&gt;
&lt;li&gt;支持创建函数索引&lt;/li&gt;
&lt;li&gt;一些基于数据库参数的函数是不应该指定为immutable的，比如timezone相关函数，是stable函数&lt;/li&gt;
&lt;li&gt;典型函数：计算1+2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;函数为什么需要有execute&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;PREPARE： parsed, analyzed, and rewritten&lt;/p&gt;
&lt;p&gt;EXECUTE： planned and executed&lt;/p&gt;
&lt;p&gt;强制SQL进行硬解析：避免SQL因为数据倾斜使用错误的执行计划。&lt;/p&gt;
&lt;p&gt;与普通SQL不同，plpgsql中默认使用Plan Caching，会自动将SQL以prepare方式执行，尝试生成和缓存generic plan 进行软解析。但是，如果有数据倾斜问题，缓存的执行计划可能是低效的，对部分核心业务来说是不可接受的。此时可以考虑使用execute语句，强制根据每个变量值生成对应执行计划，提高准确度。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/128885660" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/Hehuyi_In/article/details/128885660&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/xfunc-volatility.html" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/docs/16/xfunc-volatility.html&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;二十六、为什么要使用 create index concurrently 以及 CIC 的危害
 &lt;div id="二十六为什么要使用-create-index-concurrently-以及-cic-的危害" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%e5%8d%81%e5%85%ad%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e4%bd%bf%e7%94%a8-create-index-concurrently-%e4%bb%a5%e5%8f%8a-cic-%e7%9a%84%e5%8d%b1%e5%ae%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;why CIC:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;create index需要sharelock锁，与dml的RowExclusiveLock是冲突的，所以在线业务不应该直接使用create index。CIC使用ShareuUpdateExclusiveLock与DML锁不冲突，所以推荐使用CIC方式创建索引。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CIC的流程:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.在系统表中插入索引的元数据，包括pg_class、pg_index，然后开启两个事务，进行两次扫描
2.开启事务1，拿到当前snapshot1。
3.扫描test1表前，等待所有修改过test1表（写入、删除、更新）的事务结束。
4.扫描test1表，并建立索引。
5.结束事务1。
6.开启事务2，拿到当前snapshot2。
7.再次扫描test1表前，等待所有修改过B表（写入、删除、更新）的事务结束。
8.在snapshot2之后启动的事务对test1表执行的DML，会修改这个myidx的索引。
9.再次扫描B表，更新索引。（从TUPLE中可以拿到版本号，在snapshot1到snapshot2之间变更的记录，将其合并到索引）
10.上一步更新索引结束后，等待事务2之前开启的持有snapshot的事务结束。
11.结束索引创建。索引可见。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CIC的问题:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.先后开启两个事务，比create index多扫描一次表&lt;/p&gt;
&lt;p&gt;2.必须等待长事务结束才能开始扫描&lt;/p&gt;
&lt;p&gt;3.CIC创建的索引可能会失效&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CIC异常中断会留下失效索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CIC创建唯一索引&lt;strong&gt;过程中&lt;/strong&gt;，插入/更新的数据违反唯一约束，也会导致CIC失败留下失效索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4.失效索引仍然会因为DML的更新而更新&lt;/p&gt;
&lt;p&gt;5.分区主表不支持CIC创建索引，可在子表上以CIC一个个创建完成后，再在主表上以only方式创建索引&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/Sayutoyj7QmV5Nl8EFlwiQ" target="_blank" rel="noreferrer"&gt;学徒 深度剖析CIC&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;二十七、HOT 原理
 &lt;div id="二十七hot-原理" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8c%e5%8d%81%e4%b8%83hot-%e5%8e%9f%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;HOT：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果没有HOT，每次更新元组都会更新索引，如下新增更新一个元组，会增加一个索引条目，并且老的索引条目指向死元组。这会导致索引更新、索引空间、索引vacuum的压力。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4a5a7f3ac437.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;有HOT的情况下，页内的更新只会更新元组，不会更新索引：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e618933424af.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;HOT元组在infomask中对应HEAP_HOT_UPDATED，HEAP_ONLY_TUPLE位：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tt(a int);
&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idxtt &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tt(a);
&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; tt &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;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tt &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;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;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; tt; &lt;span style="color:#75715e"&gt;--更新完后执行一次可见性检查，让剩余的一点clog事务提交信息更新到tuple 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;
&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; 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,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;tt&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; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&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;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;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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;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&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; LP_NORMAL &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 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_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&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:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &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;4&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_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&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:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &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;5&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_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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;5&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;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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;lp(line pointer)=1的元组，通过ctid(0,2)指向第二行，第二行又指向第三行···最终指向第五行。ctid是一个链条可指向最后的那个数据行。死元组上都有HEAP_HOT_UPDATED信息，表示该元组是HOT链上已被updated的行；链最后有HEAP_ONLY_TUPLE标识，表示这是HOT链尾端的元组。&lt;/p&gt;
&lt;p&gt;有了HOT，vacuum时，只清理页内的死元组，不需要更新索引&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c220fe22e28a.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;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;vacuum&lt;/span&gt; tt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;VACUUM&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; 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,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;tt&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; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&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;5&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;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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;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&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;vacuum后死元组被清理&lt;/p&gt;
&lt;p&gt;再更新的话，又开始新的HOT链：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;update&lt;/span&gt; tt &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;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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; tt &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;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;=&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; tt;
&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; 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,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;tt&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; lp &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lp_flags &lt;span style="color:#f92672"&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;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;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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;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&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:#f92672"&gt;|&lt;/span&gt; LP_NORMAL &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 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,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;5&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;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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;新的HOT链没有从lp1开始，为什么呢？因为lp1已经被占用了，索引还指向着lp1&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; itemoffset, ctid, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; bt_page_items(&lt;span style="color:#e6db74"&gt;&amp;#39;idxtt&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; itemoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ctid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;htid (0,1) 就是page 0,lp 1。vacuum只清理了数据page，索引没有被更新，vacuum只清理了死元组合和HOT链中间的部分，ctid HOT链头尾没有动。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;INDEX ONLY SCAN：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;索引唯一扫描是各种数据中常见的、高效的索引扫描方式，它表示不需要访问数据页，只访问索引页就可以返回结果。但是这在PG中存在问题，因为可见性信息存储在数据页header中，索引页没有可见性信息，只访问索引原则上支持不了MVCC。&lt;/p&gt;
&lt;p&gt;VM文件不仅可以支持vacuum跳过表all-visible的页，还可以支持INDEX ONLY SCAN判断表all-visible的页上的tuple可见性原则：&lt;/p&gt;
&lt;p&gt;


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

&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="#%e4%ba%8c%e5%8d%81%e5%85%abpostgresql%e4%b8%ad%e6%98%af%e5%90%a6%e6%9c%89%e9%94%81%e5%8d%87%e7%ba%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;基本没有。&lt;/p&gt;
&lt;p&gt;只有Predicate lock有escalation，Predicate lock在需要做可串行化的时候才会使用，本意是锁谓词，防止数据异常现象从而实现可串行化，PG库中对应SIReadLock。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Predicate lock最细的粒度是锁某个范围内的行&lt;/li&gt;
&lt;li&gt;当行数超过一定阈值时，锁行对应的page&lt;/li&gt;
&lt;li&gt;当page超过一定阈值时，锁对应的表&lt;/li&gt;
&lt;li&gt;Predicate lock只有3种级别的锁：行、page、表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/5968020" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/5968020&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="#%e4%ba%8c%e5%8d%81%e4%b9%9d%e5%a4%8d%e5%88%b6%e6%a7%bd%e7%9a%84%e4%bd%9c%e7%94%a8%e4%bb%a5%e5%8f%8a%e5%a4%8d%e5%88%b6%e6%a7%bd%e7%9a%84%e5%8d%b1%e5%ae%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;对于物理复制，可以不需要复制槽，通过hot_standby_feedback和一些参数来管理wal。有复制槽后其实不需要这些参数，通过复制槽可以管理wal日志&lt;/p&gt;
&lt;p&gt;对于逻辑复制，必须有复制槽，相当于一个逻辑复制链路对应一个复制槽。对于逻辑复制来说，复制槽不仅管理wal日志，还负责管理逻辑解析、output plugin、解析/发送日志的位点（lsn），在复制中断后可以重传解析日志。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a3a4118829be.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;复制槽的危害：&lt;/p&gt;
&lt;p&gt;其实复制槽没有什么危害，它本身的一大功能就是简化wal日志管理的，没有复制槽仍然要制定策略管理wal日志，pg社区也推荐使用复制槽。只是需要注意，对于不需要的复制槽一定要清理，以免复制槽存储过久的位点阻止wal日志清理把磁盘打满。额外的，还要注意，DBA不要随意清理复制槽，一旦清理位点信息也没有了，下游链路可能要重新初始化数据和同步，最好是确认复制链路是否可以再次启动同步。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207" target="_blank" rel="noreferrer"&gt;pg内功修炼：逻辑复制&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="#%e4%b8%89%e5%8d%81%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e6%9c%89%e6%ad%bb%e9%94%81%e4%bb%a5%e5%8f%8a%e6%ad%bb%e9%94%81%e6%a3%80%e6%b5%8b%e6%9c%ba%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/a158c01929e8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;最简单的，事务T1持有资源1，事务T2持有资源2，如果t1尝试获得资源2，t2尝试获得资源1，此时就形成死锁。死锁如果没有管理机制可以无限期等待，所以所有DBMS都有死锁检测机制。死锁一般都以为着业务逻辑问题，如果不显示取消“环”中的某个事务来打破“环”，PG会自行检测死锁，并通过&lt;code&gt;deadlock_timeout&lt;/code&gt;（默认1s）参数来强制结束一个事务，“环”中的其他事务可以继续执行。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/blog/pgsql/5968020" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/blog/pgsql/5968020&lt;/a&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="#%e4%b8%89%e5%8d%81%e4%b8%80sql-%e6%85%a2%e8%83%bd%e4%bb%8e%e5%93%aa%e4%ba%9b%e6%96%b9%e9%9d%a2%e5%85%a5%e6%89%8b%e6%8e%92%e6%9f%a5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2e1b3f17a0b2.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%b8%89%e5%8d%81%e4%ba%8c%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e4%bd%bf%e7%94%a8%e5%88%86%e5%8c%ba%e8%a1%a8%e4%bb%a5%e5%8f%8a%e5%88%86%e5%8c%ba%e8%a1%a8%e7%9a%84%e4%bc%98%e5%8a%bf%e5%92%8c%e5%8a%a3%e5%8a%bf" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;分区表将表数据分成更小的物理分片，以此提高性能、可用性、易管理性，并且对业务透明。分区表是关系型数据库中比较常见的对大表的优化方式，数据库管理系统一般都提供了分区管理，而业务可以直接访问分区表而不需要调整业务架构，当然好的性能需要合理的分区访问方式。&lt;/p&gt;
&lt;p&gt;PG原生支持声明式分区表、继承分区表，常用插件实现的分区表有pathman。PG10开始支持声明式分区表，并在后续版本中有较多加强（详见PostgreSQL分区表-分区表的历史），建议PG12及以后使用声明式分区表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分区表的优势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SQL性能提升。在某些场景下，比如把大量的数据分成多个分区，而SQL只需要查那一个分区的数据时发生分区裁剪，SQL性能可能会极大的提升&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分区可以和索引配合使用。比如访问一个分区上的一个索引要比访问一个未分区的大索引要更高效。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;删除一个分区比删除多行数据更高效。这在时间范围分区中很常见，删除一个用不到的历史分区是非常快的，但是如果没有分区，delete删除数据不仅慢还需要额外的维护操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;vacuum更快。一个大表在回收旧版本信息或收集统计信息时会非常慢，在vacuum还没执行完的时候可能SQL已经存在问题了。如果有分区的话，vacuum会快很多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IO分散能力。不同的分区可以放在不同的路径、不同的磁盘上。极少使用数据可以放在便宜的磁盘上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更多的维护技巧。直接维护一个大表是非常困难的，比如一个极大的表做vacuum时就有很多问题，而分区表的各个分区可以单独运行vacuum。不仅如此，attach/detach、本地索引/约束等可以在很多场景中灵活使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可能使用到partition wise join或者partition wise aggregation特性&lt;/p&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;p&gt;PG中分区表也是表，表过多导致解析慢合relcache缓存表元数据过大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;表过多可能报错。参考之前的文章&lt;a href="https://editor.csdn.net/md/?articleId=131497779" target="_blank" rel="noreferrer"&gt;较少的分区也报错too many range table entries&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;即使分区过多没有报错，且在生成执行计划的时候没有做分区剪裁（执行的时候有可能做），那么explain出来的执行计划会非常多，此时日志中也会打印长长的执行计划影响日志阅读。&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PG原生分区表的几个较大的限制：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有原生的自动创建分区功能&lt;/li&gt;
&lt;li&gt;只支持分区索引，不支持全局索引&lt;/li&gt;
&lt;li&gt;主键必须包含分区键。postgresql目前只能在各自的分区内判断唯一性，所以有这个限制。oracle和mysql都没有这种限制。&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;p&gt;新分区没有数据，可以直接使用partition of（8级锁，只需注意长事务问题）添加分区表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新分区有数据，应使用attach（4级锁，不阻塞读写）方式添加分区（如有必要可以先添加新分区的分区约束，减少约束检查时间），detach concurrently（4级锁）删除分区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意attach不会像partition of那样自动创建索引、约束、默认值、行级触发器，需提前建好&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分区主表索引不支持CIC，创建分区索引的正确姿势：1主表only创建 2分区concurrently创建 3 attach所有分区索引到主索引上索引自动标记为有效。&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;a href="https://blog.csdn.net/qq_40687433/article/details/132525655" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&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="#%e4%b8%89%e5%8d%81%e4%b8%89%e8%bd%af%e7%a1%ac%e8%a7%a3%e6%9e%90%e7%9a%84%e6%a6%82%e5%bf%b5" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;硬解析&lt;/strong&gt;：对于一个SQL语句，优化器首先需要进行词法分析、语法分析，将其转换为pg能识别的查询树，再对其解析重写和优化，生成执行计划树，执行器才能知道如何执行该语句，这种完整的解析叫做硬解析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软解析&lt;/strong&gt;： 显然，如果每个语句每次都执行如此复杂的步骤，效率会很低，因此pg会将SQL解析出来的执行计划缓存在进程内存中，符合一定条件时可以直接使用，提高效率，这种解析叫做软解析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PG绑定变量SQL解析的五次机制&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;五次机制是为了防止数据倾斜，导致使用低效的执行计划。&lt;/p&gt;
&lt;p&gt;前5次执行的SQL：都根据实际传入变量生成执行计划（叫做custom plan），属于硬解析。
第6次执行的SQL：生成一个通用的执行计划（generic plan），并与前5次执行计划比较。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果不差于前5次：固定第6次的执行计划，后续即使参数再发生变化，该SQL的执行计划也不会再变，属于软解析&lt;/li&gt;
&lt;li&gt;如果差于前5次中任何一个执行计划，以后每次都重新生成执行计划，即都是硬解析。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;强制使用软/硬解析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PG 12 中引入了 force_custom_plan 参数，有以下可选值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;auto：默认，即按照五次机制处理&lt;/li&gt;
&lt;li&gt;force_custom_plan：永远进行硬解析，适用于有数据倾斜且性能和稳定性要求高的SQL&lt;/li&gt;
&lt;li&gt;force_generic_plan：永远使用generic plan，适用于没有数据倾斜或者性能和稳定性要求不高的SQL
两种计划的使用次数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG 14 在pg_prepared_statements视图中新增了generic_plans和custom_plans两列，可以看到两种计划的次数。由于pg的执行计划只是缓存在进程中，pg_prepared_statements视图只能看到本会话的SQL情况，看不到其他会话和全局信息。&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:#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; * choose_custom_plan: choose whether to use custom or generic plan
&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 defines the policy followed by GetCachedPlan.
&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;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;choose_custom_plan&lt;/span&gt;(CachedPlanSource &lt;span style="color:#f92672"&gt;*&lt;/span&gt;plansource, ParamListInfo boundParams)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;double&lt;/span&gt;		avg_custom_cost;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* Let settings force the decision */&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; (plan_cache_mode &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PLAN_CACHE_MODE_FORCE_GENERIC_PLAN)
&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; (plan_cache_mode &lt;span style="color:#f92672"&gt;==&lt;/span&gt; PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN)
&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;/* See if caller wants to force the decision */&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cursor_options &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; CURSOR_OPT_GENERIC_PLAN)
&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;cursor_options &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; CURSOR_OPT_CUSTOM_PLAN)
&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;/* Generate custom plans until we have done at least 5 (arbitrary) */&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;num_custom_plans &lt;span style="color:#f92672"&gt;&amp;lt;&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;		&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;	avg_custom_cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;total_custom_cost &lt;span style="color:#f92672"&gt;/&lt;/span&gt; plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;num_custom_plans;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Prefer generic plan if it&amp;#39;s less expensive than the average custom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * plan. (Because we include a charge for cost of planning 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;	 * custom-plan costs, this means the generic plan only has to be less
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * expensive than the execution cost plus replan cost of the custom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * plans.)
&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 that if generic_cost is -1 (indicating we&amp;#39;ve not yet determined
&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 generic plan cost), we&amp;#39;ll always prefer generic at this point.
&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;generic_cost &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; avg_custom_cost)
&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:#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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/Hehuyi_In/article/details/128885660?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170654021316800222879124%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&amp;amp;request_id=170654021316800222879124&amp;amp;biz_id=0&amp;amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-128885660-null-null.142%5ev99%5epc_search_result_base6&amp;amp;utm_term=pg%20%E9%9D%A2%E8%AF%95%E9%A2%98&amp;amp;spm=1018.2226.3001.4187" target="_blank" rel="noreferrer"&gt;Hehuyi_In 软硬解析的概念&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;三十四、vm / fsm / init 文件是什么
 &lt;div id="三十四vm--fsm--init-文件是什么" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%89%e5%8d%81%e5%9b%9bvm--fsm--init-%e6%96%87%e4%bb%b6%e6%98%af%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d0c6c3c47a5b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;**数字后缀：**文件每超过1G（默认）fork一个文件，通过./configure &amp;ndash;with-segsize在build时更改大小&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vm：&lt;/strong&gt; 页可见性文件，包含all-visible和all-frozen信息，可帮助 1）加速vacuum扫描，vacuum可跳过all-visible的页 2）加速eager freeze过程，eager freeze可跳过all-frozen页 3）支持INDEX ONLY SCAN，标记all-visible页可不用访问页本身就可以判断元组可见性&lt;/p&gt;
&lt;p&gt;**fsm：**可用空间映射文件，帮助PG定位页上的可用空间；对于索引页，由于索引是有序的，记录每个索引页的可用空间意义不大，索引的fsm文件只包含全空索引页&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;init&lt;/strong&gt;：unlogged table才有的fork文件，大小为0，相当于标记这个数据文件是unlogged的&lt;/p&gt;
&lt;p&gt;《postgresql-internals-14》&lt;/p&gt;

&lt;h3 class="relative group"&gt;三十五、内存回收机制：kswapd/direct memory reclaim/pdflush
 &lt;div id="三十五内存回收机制kswapddirect-memory-reclaimpdflush" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%89%e5%8d%81%e4%ba%94%e5%86%85%e5%ad%98%e5%9b%9e%e6%94%b6%e6%9c%ba%e5%88%b6kswapddirect-memory-reclaimpdflush" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;内存回收机制&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;后台内存回收（kswapd）：在物理内存紧张的时候，会唤醒 kswapd 内核线程来回收内存，这个回收内存的过程异步的，不会阻塞进程的执行。
直接内存回收（direct reclaim）：如果后台异步回收跟不上进程内存申请的速度，就会开始直接回收，这个回收内存的过程是同步的，会阻塞进程的执行。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/664b2fe2f965.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;&lt;strong&gt;pages_low:&lt;/strong&gt; 当可用的空闲页面数量低于pages_low 时，buddy allocator会唤醒&lt;strong&gt;kswapd&lt;/strong&gt;进程，内核开始将页换出到硬盘。
**pages_min: **当可用页面数量达到 pages_min时，说明页回收工作的压力就比较大，因为内存域中急需空闲页。分配器将以同步的方式执行 kswapd 工作，有时也称为直接内存回收（direct reclaim）。
&lt;strong&gt;pages_high:&lt;/strong&gt; 一旦 kswapd 被唤醒开始释放页面，只有在可用页面数量达到pages_high时，内核才认为该区域是“平衡的”。如果水位线达到pages_high，kswapd 将重新进入休眠状态。空闲页多于pages_high，则内核认为zone的状态是理想的。
内存回收以zone为单位进行，/proc/zoneinfo可以查看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;p&gt;&lt;strong&gt;pdflush和kcompactd&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;pdflush：pagecache中的脏页需要写入到磁盘，无论是sync（fsync等）还是操作系统调度刷脏还是数据库commit，最终都要调用到linux底层的内核线程pdflush进行刷脏工作。&lt;/p&gt;
&lt;p&gt;kcompactd：page compation是专门针对内存碎片整理的（刷脏也可以，因为内存会回收给buddy系统），与pdflush刷脏不一样，内存压缩不需要写盘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;观察内存回收&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;sar是目前 Linux 上最为全面的系统性能分析工具之一，可以从多方面对系统的活动进行报告，包括：文件的读写情况、系统调用的使用情况、磁盘 I/O、CPU 效率、内存使用状况、进程活动及 IPC 有关的活动等&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9f0b4a87e536.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;sar -B可观察到kswapd内存回收和直接内存回收：&lt;/p&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;&lt;strong&gt;pgscank/s：每秒被 kswapd 扫描的页个数&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pgscand/s：每秒直接被扫描的页个数&lt;/strong&gt;&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查看历史内存信息
&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;强推：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135492312" target="_blank" rel="noreferrer"&gt;linux内存浅析&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;三十六、进程调度，D进程的危害和形成原因
 &lt;div id="三十六进程调度d进程的危害和形成原因" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%89%e5%8d%81%e5%85%ad%e8%bf%9b%e7%a8%8b%e8%b0%83%e5%ba%a6d%e8%bf%9b%e7%a8%8b%e7%9a%84%e5%8d%b1%e5%ae%b3%e5%92%8c%e5%bd%a2%e6%88%90%e5%8e%9f%e5%9b%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;没有看太懂进程调度具体指的是什么内容，我这就以进程通信(IPC)来回答吧&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;进程通信(IPC)&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;由于虚拟地址空间中的用户空间不能被其他用户进程访问，如果通过内核区域实现多进程的用户访问同一内存数据，那么无法避免上下文切换（如下图右）。多进程的应用程序明显需要进程间的相互访问，所以一种直接可以实现用户进程访问同一物理内存的方法便应运而生，这就是共享内存（如下图左）。&lt;/p&gt;
&lt;p&gt;共享内存是实现进程相互访问IPC（inter process communication）的机制之一，其他的方式还有message queues和semaphores。共享内存是最快的IPC（inter-process communication)机制之一，因为它不需要进程间相互copy数据，进程可以通过自己的地址空间访问到共享内存。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d6a9535557f7.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.geeksforgeeks.org/inter-process-communication-ipc/）&lt;/p&gt;
&lt;p&gt;共享内存也有很多实现方式。PG中，shared_buffer默认使用mmap实现共享内存机制，对应&lt;code&gt;shared_memory_type&lt;/code&gt;参数；并行查询默认使用POSIX，对应&lt;code&gt;dynamic_shared_memory_type&lt;/code&gt;参数。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b2a8526ef63d.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;D进程&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;D进程含义：不可中断的睡眠状态。表示该进程正在等待某个外部事件完成，如磁盘I/O操作或网络请求。通常情况下，D进程不能被直接终止。&lt;/p&gt;
&lt;p&gt;D进程产生的原因：进程正在等待某个外部事件，典型的比如触发直接内存回收，它是同步的会阻塞应用程序访问磁盘，当时的磁盘访问相关进程处于D状态。注意：D进程是操作系统或硬件层面触发的，与应用程序本身关系不大（a little），比如一条PG大查询会话本身不会产生D进程，也可以被kill掉。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135492312" target="_blank" rel="noreferrer"&gt;linux内存浅析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_40687433/article/details/135541103" target="_blank" rel="noreferrer"&gt;PostgreSQL内存浅析&lt;/a&gt;&lt;/p&gt;

&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="#%e4%b8%89%e5%8d%81%e4%b8%83%e6%8a%93%e5%8c%85%e8%a7%a3%e5%8c%85%e5%88%86%e6%9e%90-postgresql-%e5%8d%8f%e8%ae%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;PG支持的协议&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;1）连接协议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TCP/IP 协议&lt;/strong&gt;： PostgreSQL 最常用的连接方式是通过 TCP/IP 协议进行通信，允许客户端和服务器在网络上进行连接和交换数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unix 域套接字（Unix domain socket）：&lt;/strong&gt; 对于位于同一台主机上的客户端和服务器之间的连接，可以使用 Unix 域套接字进行本地通信，通常比 TCP/IP 更快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSL/TLS 协议：&lt;/strong&gt; PostgreSQL 支持在 TCP/IP 连接上启用 SSL/TLS 加密，以确保数据在传输时的安全性。TLS是SSL的后续版本，PG（似乎）已经不支持SSL协议，不过相关参数还保留着供TLS使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2）密码认证协议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MD5：&lt;/strong&gt; 作为较早的默认密码认证协议，MD5（Message Digest Algorithm 5）用于在服务器端存储和验证用户密码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SCRAM-SHA-256：&lt;/strong&gt; SCRAM-SHA-256（Salted Challenge Response Authentication Mechanism with SHA-256）是一种更安全的身份验证协议，使用 SHA-256 哈希算法和挑战-响应机制来进行用户身份验证。PG10开始逐渐替代MD5。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;简单的抓包分析&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;tcpdump抓包语句：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;tcpdump tcp port &lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt; -i lo -s0 -nSX -vvv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;抓一个count(*)看看（已经通过psql -h连接到数据库里了） ：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; count&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*&lt;span style="color:#f92672"&gt;)&lt;/span&gt; from t1; --只抓这个看看
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; count 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;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;抓包内容：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;15&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828820&lt;/span&gt; IP (tos &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0, ttl &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;, id &lt;span style="color:#ae81ff"&gt;29027&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, flags [DF], proto TCP (&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;length&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;37240&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.postgres: Flags [P.], cksum &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x6d13 (incorrect &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x57c6), seq &lt;span style="color:#ae81ff"&gt;1091052893&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;1091052923&lt;/span&gt;, ack &lt;span style="color:#ae81ff"&gt;3014367256&lt;/span&gt;, win &lt;span style="color:#ae81ff"&gt;350&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;options&lt;/span&gt; [nop,nop,TS val &lt;span style="color:#ae81ff"&gt;92480460&lt;/span&gt; ecr &lt;span style="color:#ae81ff"&gt;92427582&lt;/span&gt;], &lt;span style="color:#66d9ef"&gt;length&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000: &lt;span style="color:#ae81ff"&gt;4500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0052&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7163&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4006&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;c74 ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 E..Rqc&lt;span style="color:#f92672"&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;t...U
&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;x0010: ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 &lt;span style="color:#ae81ff"&gt;9178&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1538&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4108&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;d b3ab &lt;span style="color:#ae81ff"&gt;9818&lt;/span&gt; ...U.x.&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;A.&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;0&lt;/span&gt;x0020: &lt;span style="color:#ae81ff"&gt;8018&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;015&lt;/span&gt;e &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;d13 &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;080&lt;/span&gt;a &lt;span style="color:#ae81ff"&gt;0583&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;cc ...&lt;span style="color:#f92672"&gt;^&lt;/span&gt;m.........&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;0&lt;/span&gt;x0030: &lt;span style="color:#ae81ff"&gt;0582&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;553&lt;/span&gt;e &lt;span style="color:#ae81ff"&gt;5100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;d73 &lt;span style="color:#ae81ff"&gt;656&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6563&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7420&lt;/span&gt; ..U&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;Q....&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 style="color:#ae81ff"&gt;0&lt;/span&gt;x0040: &lt;span style="color:#ae81ff"&gt;636&lt;/span&gt;f &lt;span style="color:#ae81ff"&gt;756&lt;/span&gt;e &lt;span style="color:#ae81ff"&gt;7428&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;a29 &lt;span style="color:#ae81ff"&gt;2066&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;726&lt;/span&gt;f &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;d20 &lt;span style="color:#ae81ff"&gt;7431&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;.t1
&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;x0050: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;b00 ;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;830090&lt;/span&gt; IP (tos &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0, ttl &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;, id &lt;span style="color:#ae81ff"&gt;49370&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, flags [DF], proto TCP (&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;length&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;115&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.postgres &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;37240&lt;/span&gt;: Flags [P.], cksum &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x6d34 (incorrect &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x6e5c), seq &lt;span style="color:#ae81ff"&gt;3014367256&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3014367319&lt;/span&gt;, ack &lt;span style="color:#ae81ff"&gt;1091052923&lt;/span&gt;, win &lt;span style="color:#ae81ff"&gt;342&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;options&lt;/span&gt; [nop,nop,TS val &lt;span style="color:#ae81ff"&gt;92480461&lt;/span&gt; ecr &lt;span style="color:#ae81ff"&gt;92480460&lt;/span&gt;], &lt;span style="color:#66d9ef"&gt;length&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; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0000: &lt;span style="color:#ae81ff"&gt;4500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0073&lt;/span&gt; c0da &lt;span style="color:#ae81ff"&gt;4000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4006&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;cdc ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 E..s..&lt;span style="color:#f92672"&gt;@&lt;/span&gt;.&lt;span style="color:#f92672"&gt;@&lt;/span&gt;......U
&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;x0010: ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 &lt;span style="color:#ae81ff"&gt;1538&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9178&lt;/span&gt; b3ab &lt;span style="color:#ae81ff"&gt;9818&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4108&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;257&lt;/span&gt;b ...U.&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;.x....A.&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;x0020: &lt;span style="color:#ae81ff"&gt;8018&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0156&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;d34 &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;080&lt;/span&gt;a &lt;span style="color:#ae81ff"&gt;0583&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;cd ...Vm4........&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;0&lt;/span&gt;x0030: &lt;span style="color:#ae81ff"&gt;0583&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;cc &lt;span style="color:#ae81ff"&gt;5400&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;e00 &lt;span style="color:#ae81ff"&gt;0163&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;f75 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;e74 ..&lt;span style="color:#f92672"&gt;#&lt;/span&gt;.T......&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:#ae81ff"&gt;0&lt;/span&gt;x0040: &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1400&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;ff ffff ................
&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;x0050: ff00 &lt;span style="color:#ae81ff"&gt;0044&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;000&lt;/span&gt;b &lt;span style="color:#ae81ff"&gt;0001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3443&lt;/span&gt; ...D..........&lt;span style="color:#ae81ff"&gt;4&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:#ae81ff"&gt;0&lt;/span&gt;x0060: &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;000&lt;/span&gt;d &lt;span style="color:#ae81ff"&gt;5345&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;c45 &lt;span style="color:#ae81ff"&gt;4354&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2031&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;005&lt;/span&gt;a &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; ....&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.Z..
&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;x0070: &lt;span style="color:#ae81ff"&gt;0005&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; ..I
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;830098&lt;/span&gt; IP (tos &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x0, ttl &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;, id &lt;span style="color:#ae81ff"&gt;29028&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, flags [DF], proto TCP (&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;length&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;37240&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;.postgres: Flags [.], cksum &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x6cf5 (incorrect &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;x5cb9), seq &lt;span style="color:#ae81ff"&gt;1091052923&lt;/span&gt;, ack &lt;span style="color:#ae81ff"&gt;3014367319&lt;/span&gt;, win &lt;span style="color:#ae81ff"&gt;350&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;options&lt;/span&gt; [nop,nop,TS val &lt;span style="color:#ae81ff"&gt;92480461&lt;/span&gt; ecr &lt;span style="color:#ae81ff"&gt;92480461&lt;/span&gt;], &lt;span style="color:#66d9ef"&gt;length&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;0&lt;/span&gt;x0000: &lt;span style="color:#ae81ff"&gt;4500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0034&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7164&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4006&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;c91 ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 E..&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;qd&lt;span style="color:#f92672"&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;....U
&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;x0010: ac12 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;a55 &lt;span style="color:#ae81ff"&gt;9178&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1538&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4108&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;257&lt;/span&gt;b b3ab &lt;span style="color:#ae81ff"&gt;9857&lt;/span&gt; ...U.x.&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;A.&lt;span style="color:#f92672"&gt;%&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;...W
&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;x0020: &lt;span style="color:#ae81ff"&gt;8010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;015&lt;/span&gt;e &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;cf5 &lt;span style="color:#ae81ff"&gt;0000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;080&lt;/span&gt;a &lt;span style="color:#ae81ff"&gt;0583&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;cd ...&lt;span style="color:#f92672"&gt;^&lt;/span&gt;l.........&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;0&lt;/span&gt;x0030: &lt;span style="color:#ae81ff"&gt;0583&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;cd ..&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;肉眼看报文···可以简单分析出，这个count语句只产生了3个报文，甚至可以看到select.count(*).from.t1语句&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;wireshark分析报文&lt;/strong&gt;：&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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tcpdump tcp port &lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt; -i lo -s0 -nSX -vvv -w tcpdump.cap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;窗口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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;iZ2vcdugd3f2h0t7x20pqmZ &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; psql &lt;span style="color:#f92672"&gt;-&lt;/span&gt;h &lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;85&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;p &lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#f92672"&gt;-&lt;/span&gt;U lzl &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;Password &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt; lzl: &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;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:#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; t1; &lt;span style="color:#75715e"&gt;--步骤3，查个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;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;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;q &lt;span style="color:#75715e"&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;注意有4个步骤，至少对应报文的4个部分内容&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;步骤1-请求连接&lt;/li&gt;
&lt;li&gt;步骤2-输入密码&lt;/li&gt;
&lt;li&gt;步骤3-查个SQL&lt;/li&gt;
&lt;li&gt;步骤4-退出连接&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;包抓好，下面开始用&lt;a href="https://www.wireshark.org/download.html" target="_blank" rel="noreferrer"&gt;wireshark&lt;/a&gt;分析tcpdump.cap的报文。&lt;/p&gt;
&lt;p&gt;1)步骤1-请求连接[1-10]——TCP三次握手[1-3]：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d79f57937f52.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;37282-&amp;gt;5432发送SYN，seq=0&lt;/li&gt;
&lt;li&gt;5432-&amp;gt;37282发送SYN+ACK，seq=0 ack=1&lt;/li&gt;
&lt;li&gt;37282-&amp;gt;5432发送ACK，seq=1 ack=1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2c2b65905d60.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（https://www.researchgate.net/publication/340247809_Computer_Network_Chapter_8_Transport_Layer_UDP_and_TCP）&lt;/p&gt;
&lt;p&gt;2)步骤1-请求连接[1-10]——pgsql协议启动和认证请求[4-7]：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f1fe82c3a6ce.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;三次握手完成后，PSQL客户端立即向PG server发送开始建立PGSQL协议的消息[4]，info为&amp;gt;?，为协议启动消息&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/376c522b4dd8.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;上面的&amp;gt;?报文是37282-&amp;gt;5432，其实不用专门在Transmission Control Protocol中看source和destination。PGSQL协议虽然比TCP协议在info上展示的信息更少，但它也是有方向的：&amp;gt;表示37282-&amp;gt;5432，&amp;lt;表示37282&amp;lt;-5432。&lt;/p&gt;
&lt;p&gt;随后第二个PGSQL协议是认证请求[6]，info为&amp;lt;R，37282&amp;lt;-5432。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/e0135443ee2d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;3)步骤1-请求连接[1-10]——三次挥手[8-10]。在server向client发送PGSQL协议认证请求后，client请求断开TCP协议，3次TCP挥手（注意不是4次挥手，下面会提及）。注意此时psql命令行的状态是等待输入密码···&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/7a7094b99256.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;4)步骤2-输入密码[11-22]——三次握手[11-13]。因为第一次TCP协议结束了，建连接还得从TCP开始···所以得先开始第二次TCP协议三次握手：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/dd0ed1d5110b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;5）步骤2-输入密码[11-22]——密码认证[14-22]。认证阶段稍微复杂一些。[14-16]实际上跟步骤1中的[4-7]做的事情是一样的，client请求启动PGSQL协议，server返回认证需求。随后[18-20]都是在做密码认证，密码认证机制为&lt;strong&gt;SCRAM-SHA-256&lt;/strong&gt;，密码认证其实传了4个报文，包括[21]的两个R认证消息。随后[21]连接建立，前两个R是认证完成消息；中间有很多S表示Parameter status：应用名、字符集、时区等等参数信息；K表示Backend key，返回fork出来的backend PID；Z表示ready for query。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/969f8aba1e26.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;5）步骤3-查个SQL[23-25]&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d68d274be7ab.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;[23]Q明显代表query，client发出包含SQL的报文；[24]返回结果，T代表Row Description，这里只包含列名count；D代表data row数据行，这里的返回的count结果为4，数据没有加密是明文的：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/49c15b851c3e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;C代表命令完成；Z代表ready。&lt;/p&gt;
&lt;p&gt;5）步骤4-断开连接[26-29]。[26]client主动发出结束会话的消息，PGSQL协议（对应\q)；[27-29]仍然是3次TCP挥手过程。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/9fb2ec1fbc1a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;为啥是三次挥手而不是此次挥手？&lt;/p&gt;
&lt;p&gt;「没有数据要发送」并且「开启了 TCP 延迟确认机制」，那么第二和第三次挥手就会合并传输，这样就出现了三次挥手：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d0fa97105c11.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（&lt;a href="https://www.xiaolincoding.com/network/3_tcp/tcp_three_fin.html#tcp-%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B" target="_blank" rel="noreferrer"&gt;TCP 四次挥手，可以变成三次吗？&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;因为 TCP 延迟确认机制是默认开启的，所以导致我们抓包时，看见三次挥手的次数比四次挥手还多。&lt;/p&gt;
&lt;p&gt;OK，PG的简单抓包和分析完成。汇总一个本次分享的Postgres网络传输图：



&lt;img src="https://lastdba.com/img/csdn/8c246946c86e.png" alt="在这里插入图片描述" /&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;p&gt;&lt;a href="https://mp.weixin.qq.com/s/dF4juaW-ttI0Zn1j0z6tag" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/dF4juaW-ttI0Zn1j0z6tag&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;丢包&lt;/strong&gt;会涉及到⽹卡、驱动、内核协议栈三⼤类，每一层都有可能会丢包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在两台 VM 连接之间，可能会发生传输失败的错误，比如网络拥塞、线路错误等；&lt;/li&gt;
&lt;li&gt;在网卡收包后，环形缓冲区可能会因为溢出而丢包；&lt;/li&gt;
&lt;li&gt;在 IP 层，可能会因为路由失败、组包大小超过 MTU 等而丢包；&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;/p&gt;
&lt;p&gt;&lt;a href="https://www.twblogs.net/a/5cbca833bd9eee0eff4612ff/?lang=zh-cn" target="_blank" rel="noreferrer"&gt;Tcpdump一次抓包记录（Postgresql通信）&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/s/dF4juaW-ttI0Zn1j0z6tag" target="_blank" rel="noreferrer"&gt;学徒 DBA必备技能之网络丢包分析总结&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pigsty.cc/zh/blog/2018/01/05/pgsql%E5%8D%8F%E8%AE%AE%E5%88%86%E6%9E%90%E7%BD%91%E7%BB%9C%E6%8A%93%E5%8C%85/" target="_blank" rel="noreferrer"&gt;PgSQL协议分析:网络抓包&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.xiaolincoding.com/network/3_tcp/tcp_three_fin.html#tcp-%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B" target="_blank" rel="noreferrer"&gt;TCP 四次挥手，可以变成三次吗？&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;三十八、存储，SAN/NAS/DAS
 &lt;div id="三十八存储sannasdas" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%89%e5%8d%81%e5%85%ab%e5%ad%98%e5%82%a8sannasdas" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


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

&lt;h3 class="relative group"&gt;三十九、一条 IO 请求的生命周期
 &lt;div id="三十九一条-io-请求的生命周期" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%89%e5%8d%81%e4%b9%9d%e4%b8%80%e6%9d%a1-io-%e8%af%b7%e6%b1%82%e7%9a%84%e7%94%9f%e5%91%bd%e5%91%a8%e6%9c%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4e36321eb908.png" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;（https://blog.csdn.net/Hehuyi_In/article/details/100715177?spm=1001.2014.3001.5501）&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>vacuum啥时候截断末尾页？</title><link>https://lastdba.com/2024/08/12/vacuum%E5%95%A5%E6%97%B6%E5%80%99%E6%88%AA%E6%96%AD%E6%9C%AB%E5%B0%BE%E9%A1%B5/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/vacuum%E5%95%A5%E6%97%B6%E5%80%99%E6%88%AA%E6%96%AD%E6%9C%AB%E5%B0%BE%E9%A1%B5/</guid><description>&lt;h2 class="relative group"&gt;vacuum truncate
 &lt;div id="vacuum-truncate" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vacuum-truncate" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;TRUNCATE&amp;mdash;Specifies that &lt;code&gt;VACUUM&lt;/code&gt; should attempt to truncate off any empty pages at the end of the table and allow the disk space for the truncated pages to be returned to the operating system. This is normally the desired behavior and is the default unless the &lt;code&gt;vacuum_truncate&lt;/code&gt; option has been set to false for the table to be vacuumed. Setting this option to false may be useful to avoid &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock on the table that the truncation requires. This option is ignored if the &lt;code&gt;FULL&lt;/code&gt; option is used.&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;vacuum truncate
 &lt;div id="vacuum-truncate" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vacuum-truncate" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;TRUNCATE&amp;mdash;Specifies that &lt;code&gt;VACUUM&lt;/code&gt; should attempt to truncate off any empty pages at the end of the table and allow the disk space for the truncated pages to be returned to the operating system. This is normally the desired behavior and is the default unless the &lt;code&gt;vacuum_truncate&lt;/code&gt; option has been set to false for the table to be vacuumed. Setting this option to false may be useful to avoid &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock on the table that the truncation requires. This option is ignored if the &lt;code&gt;FULL&lt;/code&gt; option is used.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;AKA，vacuum操作中的truncate选项是默认打开的，它会把表末尾的pages移除，移除的时候会获得一个表上的8级锁。
今天发现某个环境上delete from删除完所有数据后，autovacuum自动触发或者手动跑vacuum，都不会回收空间。
重现问题:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; lzl1(a int);
&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; lzl1 &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;1000&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;analyze&lt;/span&gt; lzl1;&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;lzldb=# select relname,relpages,reltuples from pg_class where relname=&amp;#39;lzl1&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname | relpages | reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl1 | 5 | 1000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在relpage是5，最后一个页的页号是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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lzldb=&amp;gt; select t_ctid,lp,case lp_flags when 0 then &amp;#39;0:LP_UNUSED&amp;#39; when 1 then &amp;#39;LP_NORMAL&amp;#39; when 2 then &amp;#39;LP_REDIRECT&amp;#39; when 3 then &amp;#39;LP_DEAD&amp;#39; end as lp_flags,t_xmin,t_xmax,t_field3 as t_cid, raw_flags, info.combined_flags,substring(t_data,0,40) from heap_page_items(get_raw_page(&amp;#39;lzl1&amp;#39;,4)) item,LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) info order by lp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t_ctid | lp | lp_flags | t_xmin | t_xmax | t_cid | raw_flags | combined_flags | substring 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--------+----+-----------+--------+--------+-------+-----------------------------------------+----------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (4,1) | 1 | LP_NORMAL | 772 | 0 | 0 | {HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID} | {} | \x89030000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (4,2) | 2 | LP_NORMAL | 772 | 0 | 0 | {HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID} | {} | \x8a030000
&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:#66d9ef"&gt;delete&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;&lt;span style="color:#66d9ef"&gt;vacuum&lt;/span&gt; lzl1;&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:#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;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 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;4&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;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:#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;0&lt;/span&gt;:LP_UNUSED &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; &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;select&lt;/span&gt; relname,relpages,reltuples &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;lzl1&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; relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl2 &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;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并没有回收
为什么表里面都没有数据了还不做截断操作？带着这个问题来一探究竟。&lt;/p&gt;

&lt;h2 class="relative group"&gt;should_attempt_truncation函数源码分析
 &lt;div id="should_attempt_truncation函数源码分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#should_attempt_truncation%e5%87%bd%e6%95%b0%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;（未声明版本的都是PG11）
在vacuumlazy.c中有一个言简意赅的函数&lt;code&gt;should_attempt_truncation&lt;/code&gt;，这个就是判断是否需要做truncation的函数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;should_attempt_truncation&lt;/span&gt;(LVRelStats &lt;span style="color:#f92672"&gt;*&lt;/span&gt;vacrelstats)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BlockNumber possibly_freeable;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	possibly_freeable &lt;span style="color:#f92672"&gt;=&lt;/span&gt; vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rel_pages &lt;span style="color:#f92672"&gt;-&lt;/span&gt; vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nonempty_pages;
&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; (possibly_freeable &lt;span style="color:#f92672"&gt;&amp;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;		(possibly_freeable &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; REL_TRUNCATE_MINIMUM &lt;span style="color:#f92672"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		 possibly_freeable &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rel_pages &lt;span style="color:#f92672"&gt;/&lt;/span&gt; REL_TRUNCATE_FRACTION) &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;		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 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:#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&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define REL_TRUNCATE_MINIMUM 1000
&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 REL_TRUNCATE_FRACTION 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;所以是否truncation的判断逻辑必须满足以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;末尾空page数大于1000 或 末尾空page数大于总page数的1/16&lt;/li&gt;
&lt;li&gt;old_snapshot_threshold&amp;lt;0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一个规则是为了不用老是去截断那先零零碎碎的末尾空page，这回收不了多少空间，不仅浪费时间还浪费8级锁，没有必要。
第二个规则是这样解释的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; Also don&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t attempt it &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; we are doing early pruning&lt;span style="color:#f92672"&gt;/&lt;/span&gt;vacuuming, because a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; scan which cannot find a truncated heap page cannot determine that 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; snapshot is too old to read that page. We might be able to get away with
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; truncating all except one of the pages, setting its LSN &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; (at least) 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; maximum of the truncated range &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; we also treated an index leaf tuple
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; pointing to a missing heap page as something to trigger the &lt;span style="color:#e6db74"&gt;&amp;#34;snapshot too&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; old&lt;span style="color:#e6db74"&gt;&amp;#34; error, but that seems fragile and seems like it deserves its own patch&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;if&lt;/span&gt; we consider it.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;“因为vacuum扫描还不能确认page上的数据是否有快照过久问题，里面还有些LSN、索引页问题，代码逻辑看起来很琐碎，如果需要这个功能的话，需要一个patch来解决这个问题”
OK，看起来就是没有去判断page是否真的有快照过久问题，那么简单粗暴地以old_snapshot_threshold&amp;lt;0来判断，数据库本身关闭了快照过久问题，才会去truncation。&lt;/p&gt;
&lt;p&gt;回到之前的vacuum没有回收的问题，因为是delete删除了所有数据，所以肯定满足“末尾空page数大于总page数的1/16”，然而环境中的old_snapshot_threshold确是打开的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;show&lt;/span&gt; old_snapshot_threshold ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; old_snapshot_threshold 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;关闭old_snapshot_threshold再去做这个delete全表+vacuum就会回收了。关闭old_snapshot_threshold需要重启数据库。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; old_snapshot_threshold ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; old_snapshot_threshold 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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:#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;=&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;lzl1&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;16384&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16446&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;vacuum&lt;/span&gt; lzl1; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--pages成功回收
&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,relpages,reltuples &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;lzl1&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; relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl1 &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:#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; pg_relation_filepath(&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; 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;16384&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16446&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pages全部成功回收，表没有重建。问题就算定位完了。
不过为了更进一步了解vacuum truncation机制，还可以继续看看下面的章节。&lt;/p&gt;

&lt;h2 class="relative group"&gt;lazy_truncate_heap函数源码分析
 &lt;div id="lazy_truncate_heap函数源码分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#lazy_truncate_heap%e5%87%bd%e6%95%b0%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;仅仅通过&lt;code&gt;should_attempt_truncation&lt;/code&gt;函数来判断是否truncation还不严谨，还要看一眼真正执行truncation的函数&lt;code&gt;lazy_truncate_heap&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; * lazy_truncate_heap - try to truncate off any empty pages at the end
&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;lazy_truncate_heap&lt;/span&gt;(Relation onerel, LVRelStats &lt;span style="color:#f92672"&gt;*&lt;/span&gt;vacrelstats)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BlockNumber old_rel_pages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rel_pages;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	BlockNumber new_rel_pages;
&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;			lock_retry;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* Report that we are now truncating */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;pgstat_progress_update_param&lt;/span&gt;(PROGRESS_VACUUM_PHASE,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								 PROGRESS_VACUUM_PHASE_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;	 * Loop until no more truncating can be done.
&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;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		PGRUsage	ru0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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_rusage_init&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ru0);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 need full exclusive lock on the relation in order 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;		 * truncation. If we can&amp;#39;t get it, give up rather than waiting --- 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;		 * don&amp;#39;t want to block other backends, and we don&amp;#39;t want to deadlock
&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 quite possible considering we already hold a lower-grade
&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).
&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;		vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lock_waiter_detected &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;		lock_retry &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;while&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;//如果可以获得锁，break while
&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;ConditionalLockRelation&lt;/span&gt;(onerel, AccessExclusiveLock))
&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:#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 for interrupts while trying to (re-)acquire the exclusive
&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.
&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;CHECK_FOR_INTERRUPTS&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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_retry)=1，不大于100；当大于100时，不做truncation直接返回
&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;lock_retry &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (VACUUM_TRUNCATE_LOCK_TIMEOUT &lt;span style="color:#f92672"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 failed to establish the lock in the specified number of
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;				 * retries. This means we give up truncating.
&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;				vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lock_waiter_detected &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:#a6e22e"&gt;ereport&lt;/span&gt;(elevel,
&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;&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;: stopping truncate due to conflicting lock request&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;RelationGetRelationName&lt;/span&gt;(onerel))));
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;//sleep 50ms，看起来有点笨。理论上最长可以等50*100=5s
&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_usleep&lt;/span&gt;(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000L&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;//当我们拿到排他锁后，查看vacuum过程中是否有新元组，如有则不做truncation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		new_rel_pages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RelationGetNumberOfBlocks&lt;/span&gt;(onerel);
&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; (new_rel_pages &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; old_rel_pages)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;UnlockRelation&lt;/span&gt;(onerel, AccessExclusiveLock);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		new_rel_pages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count_nondeletable_pages&lt;/span&gt;(onerel, vacrelstats);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//如果vacuum过程中有新元组写入，不做truncation
&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; (new_rel_pages &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; old_rel_pages)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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&amp;#39;t do anything after all */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;UnlockRelation&lt;/span&gt;(onerel, AccessExclusiveLock);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#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;		 * Okay to truncate.
&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;RelationTruncate&lt;/span&gt;(onerel, new_rel_pages);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;//truncation后立即释放锁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;UnlockRelation&lt;/span&gt;(onerel, AccessExclusiveLock);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;while&lt;/span&gt; (new_rel_pages &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;nonempty_pages &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;			 vacrelstats&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;lock_waiter_detected);
&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL 50 &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 VACUUM_TRUNCATE_LOCK_TIMEOUT 5000 &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;真正调用的主题函数是RelationTruncate，前面一大截都是在尝试获取AccessExclusiveLock。除了之前说的2个条件外，还有以下两种情况不会做truncation&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有获得AccessExclusiveLock&lt;/li&gt;
&lt;li&gt;vacuum过程中有新数据写入&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;vacuum truncate可能会等待5秒
 &lt;div id="vacuum-truncate可能会等待5秒" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vacuum-truncate%e5%8f%af%e8%83%bd%e4%bc%9a%e7%ad%89%e5%be%855%e7%a7%92" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;上面翻&lt;code&gt;lazy_truncate_heap&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL * 1000L);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里每次循环会等待50ms，理论上最长可以等50*100=5s！
测试一把这个等待时间：&lt;/p&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;create table lzl2;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;alter table lzl2 set (autovacuum_enabled=off);;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;insert into lzl2 select generate_series(1,1000) a;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;delete from lzl2;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;begin;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;select * from lzl2;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;\timing&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;vacuum lzl2; &amp;ndash;Time: 5022.122 ms (00:05.022)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;可以看到等待时间约5s。&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;手速快的话还可以再开个窗口抓下会话2的pstack&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-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;cncq081298 lzl]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pstack &lt;span style="color:#ae81ff"&gt;4113&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#0 0x00002b92a978c013 in __select_nocancel () from /lib64/libc.so.6
&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 0x000000000086225a in pg_usleep (microsec=microsec@entry=50000) at pgsleep.c:56
&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 0x00000000005e8212 in lazy_truncate_heap (vacrelstats=0xfc4490, onerel=0x2b92a8bc88d8) at vacuumlazy.c:1861
&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 lazy_vacuum_rel (onerel=onerel@entry=0x2b92a8bc88d8, options=options@entry=5, params=params@entry=0x7ffc96bb31d0, bstrategy=&amp;lt;optimized out&amp;gt;) at vacuumlazy.c:290
&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 0x00000000005e4551 in vacuum_rel (relid=32778, relation=&amp;lt;optimized out&amp;gt;, options=options@entry=5, params=params@entry=0x7ffc96bb31d0) at vacuum.c:1572
&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 0x00000000005e55ac in vacuum (options=5, relations=0xfc6540, params=params@entry=0x7ffc96bb31d0, bstrategy=&amp;lt;optimized out&amp;gt;, bstrategy@entry=0x0, isTopLevel=isTopLevel@entry=true) at vacuum.c:340
&lt;/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;lazy_truncate_heap&lt;/code&gt;上的&lt;code&gt;pg_usleep &lt;/code&gt;，传入&lt;code&gt;entry=50000 microsec&lt;/code&gt;，实际上&lt;code&gt;pg_usleep&lt;/code&gt;循环了100次，总等待时间是50000*100 microsec=5s。&lt;/p&gt;
&lt;p&gt;后来PG15这段代码更优化了，把pg_usleep改成WaitLatch&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#a6e22e"&gt;WaitLatch&lt;/span&gt;(MyLatch,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WL_LATCH_SET &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WL_TIMEOUT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; WL_EXIT_ON_PM_DEATH,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WAIT_EVENT_VACUUM_TRUNCATE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ResetLatch&lt;/span&gt;(MyLatch);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;vacuum truncate小结
 &lt;div id="vacuum-truncate小结" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vacuum-truncate%e5%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;vacuum触发truncation的条件（且）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;末尾空page数大于1000 或 末尾空page数大于总page数的1/16&lt;/li&gt;
&lt;li&gt;old_snapshot_threshold&amp;lt;0&lt;/li&gt;
&lt;li&gt;PG15（不含）以前需要在5s内获得8级锁AccessExclusiveLock&lt;/li&gt;
&lt;li&gt;vacuum过程中没有新数据写入&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>案例-insert value偶发慢分析</title><link>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B-insert-value%E5%81%B6%E5%8F%91%E6%85%A2%E5%88%86%E6%9E%90/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B-insert-value%E5%81%B6%E5%8F%91%E6%85%A2%E5%88%86%E6%9E%90/</guid><description>&lt;p&gt;业务insert value偶发变慢，当我去查看活动会话的时候写入慢问题已经缓解了。
后来发现写入慢问题持续不到半分钟，insert value写入时间1-2s，写个抓活动会话的脚本还是能拿到会话信息：&lt;/p&gt;</description><content:encoded>&lt;p&gt;业务insert value偶发变慢，当我去查看活动会话的时候写入慢问题已经缓解了。
后来发现写入慢问题持续不到半分钟，insert value写入时间1-2s，写个抓活动会话的脚本还是能拿到会话信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; wait_event &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:#66d9ef"&gt;null&lt;/span&gt;] &lt;span style="color:#f92672"&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; WALRead &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; DataFileRead &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; BgWriterMain &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; WALWrite &lt;span style="color:#f92672"&gt;|&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; AutoVacuumMain &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; ClientRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;385&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LogicalLauncherMain &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;等待事件最异常的就是WALWrite 40个会话。
其中2个WALWrite等待的会话如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xact_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; state_change &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; partofquery
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;144955&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;516574&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;516588&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1( 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;179869&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;116371&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;116386&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1( &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;直接搜源码关于WALWrite的相关内容&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; WALWriteLock: must be held to write WAL buffers to &lt;span style="color:#a6e22e"&gt;disk&lt;/span&gt; (XLogWrite or
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; XLogFlush).&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;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* LWLockAcquireOrWait - Acquire lock, or wait until it&amp;#39;s free
&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 semantics of this function are a bit funky. If the lock is 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;* free, it is acquired in the given mode, and the function returns true. 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;* the lock isn&amp;#39;t immediately free, the function waits until it is released
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* and returns false, but does not acquire the 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;*
&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 is currently used for WALWriteLock: when a backend flushes the WAL,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* holding WALWriteLock, it can flush the commit records of many other
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* backends as a side-effect. Those other backends need to wait until 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;* flush finishes, but don&amp;#39;t need to acquire the lock anymore. They can just
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;* wake up, observe that their records have already been flushed, and return.
&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;wal从wal buffer写入磁盘时，必须持有WALWriteLock。
当backend刷wal时，持有WALWriteLock，它也能刷其他backends提交记录。其他backends需要等这个flush完成，但不需要再去持有锁了。如果他们的wal被刷了，他们能直接返回（而不是再去刷一次wal）。&lt;/p&gt;
&lt;p&gt;XLogFlush极其重要， XLogFlush的关键代码在for循环里：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Ensure that all XLOG data through the given position is flushed 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; * NOTE: this differs from XLogWrite mainly in that the WALWriteLock is 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; * already held, and we try to avoid acquiring it if possible.
&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;XLogFlush&lt;/span&gt;(XLogRecPtr 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:#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;	 * Now wait until we get the write lock, or someone else does the flush
&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 us.
&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;for&lt;/span&gt; (;;)
&lt;/span&gt;&lt;/span&gt;&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	insertpos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 LogwrtResult and update local state */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SpinLockAcquire&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;info_lck);
&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; (WriteRqstPtr &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;LogwrtRqst.Write)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			WriteRqstPtr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;LogwrtRqst.Write;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		LogwrtResult &lt;span style="color:#f92672"&gt;=&lt;/span&gt; XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;LogwrtResult;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SpinLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;info_lck);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* done already? */&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; (record &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; LogwrtResult.Flush)
&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:#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 actually performing the write, wait for all in-flight
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * insertions to the pages we&amp;#39;re about to write to finish.
&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;		insertpos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WaitXLogInsertionsToFinish&lt;/span&gt;(WriteRqstPtr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;		 * Try to get the write lock. If we can&amp;#39;t get it immediately, wait
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * until it&amp;#39;s released, and recheck if we still need to do the flush
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * or if the backend that held the lock did it for us already. 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;		 * helps to maintain a good rate of group committing when the system
&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 bottlenecked by the speed of fsyncing.
&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;LWLockAcquireOrWait&lt;/span&gt;(WALWriteLock, 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;/*
&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 lock is now free, but we didn&amp;#39;t acquire it yet. Before 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;			 * do, loop back to check if someone else flushed the record 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;			 * us 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;			 */&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* Got the lock; recheck whether request is satisfied */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		LogwrtResult &lt;span style="color:#f92672"&gt;=&lt;/span&gt; XLogCtl&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;LogwrtResult;
&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; (record &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; LogwrtResult.Flush)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;(WALWriteLock);
&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 style="color:#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;		 * Sleep before flush! By adding a delay here, we may give further
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * backends the opportunity to join the backlog of group 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;		 * followers; this can significantly improve transaction throughput,
&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 the risk of increasing transaction latency.
&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 do not sleep if enableFsync is not turned on, nor if there are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * fewer than CommitSiblings other backends with active transactions.
&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; (CommitDelay &lt;span style="color:#f92672"&gt;&amp;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; enableFsync &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;MinimumActiveBackends&lt;/span&gt;(CommitSiblings))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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_usleep&lt;/span&gt;(CommitDelay);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;			 * Re-check how far we can now flush the WAL. It&amp;#39;s generally 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;			 * safe to call WaitXLogInsertionsToFinish while holding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * WALWriteLock, because an in-progress insertion might need 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;			 * also grab WALWriteLock to make progress. But we know that all
&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 insertions up to insertpos have already finished, because
&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&amp;#39;s what the earlier WaitXLogInsertionsToFinish() 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;			 * We&amp;#39;re only calling it again to allow insertpos to be 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;			 * further forward, not to actually wait for anyone.
&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;			insertpos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WaitXLogInsertionsToFinish&lt;/span&gt;(insertpos);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* try to write/flush later additions to XLOG as well */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		WriteRqst.Write &lt;span style="color:#f92672"&gt;=&lt;/span&gt; insertpos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		WriteRqst.Flush &lt;span style="color:#f92672"&gt;=&lt;/span&gt; insertpos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;XLogWrite&lt;/span&gt;(WriteRqst, 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;LWLockRelease&lt;/span&gt;(WALWriteLock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* done */&lt;/span&gt;
&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;XLogFlush函数是刷脏WAL的主要函数：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;判断需要flush的脏WAL是否已经被其他人flush了，如是，则直接返回&lt;/li&gt;
&lt;li&gt;尝试以排他模式获得锁WALWriteLock，不断尝试，直到获得锁为止&lt;/li&gt;
&lt;li&gt;拿到锁了，再次检查需要flush的脏WAL是否已经被其他人flush了，如是，则释放WALWriteLock，然后返回（申请锁期间也有可能脏WAL被其他人flush，如果是当然什么也不用做）&lt;/li&gt;
&lt;li&gt;等待commit_delay毫秒且并发提交事务数大于commit_siblings，更新wal的写入点，形成组提交 。这一步目前走不到，因为CommitDelay默认为0，相当于没有打开组提交&lt;/li&gt;
&lt;li&gt;调用XLogWrite写日志，写完释放WALWriteLock&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;XLogFlush刷脏wal需要判断当前请求的脏wal是不是已经写了，如果没写，会持有WALWriteLock直到XLogWrite函数日志写入完成。XLogWrite是写wal的具体函数，如写如到哪个page的哪个位置。&lt;/p&gt;
&lt;p&gt;回到之前活动会话的等待事件上。IO:WALWrite等待IO比较好理解，LWLOCK:WALWrite怎么去确认是不是问题呢？
从XLogFlush函数逻辑可知，WALWriteLock是pg在写脏wal时申请的排他LWlock（这很好理解，wal的提交信息是顺序写的，只能给排他模式写，不能谁写的快就谁写，不然数据容易出错），是串行的写wal提交信息。
了解这部分逻辑再回去看pg_stat_activity，会发现IO:WALWrite&lt;strong&gt;只有1个&lt;/strong&gt;，而LWLOCK:WALWrite有几十个。
虽然不能直接看到LWLOCK的blocking chain，但是我们可以从源码中得知，&lt;strong&gt;LWLOCK:WALWrite在等待IO:WALWrite&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/16/wal-configuration.html" target="_blank" rel="noreferrer"&gt;官方文档&lt;/a&gt;有一段关于XLogFlush和调整wal buffer的描述：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Normally, WAL buffers should be written and flushed by an XLogFlush request, which is made, for the most part, at transaction commit time to ensure that transaction records are flushed to permanent storage. On systems with high WAL output, XLogFlush requests might not occur often enough to prevent XLogInsertRecord from having to do writes. On such systems one should increase the number of WAL buffers by modifying the wal_buffers parameter. When full_page_writes is set and the system is very busy, setting wal_buffers higher will help smooth response times during the period immediately following each checkpoint.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;正常情况下，wal buffer会被XLogFlush flush，例如事务提交写wal日志到磁盘上。如果wal日志量很大，但是XLogFlush触发不频繁（也就是全是大事务），就需要XLogInsertRecord写没有提交的wal record，也就是说wal_buffer不够用了，此时增大wal_buffer会稍微对系统的响应时间有帮助。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;There are two commonly used internal WAL functions: XLogInsertRecord and XLogFlush. XLogInsertRecord is used to place a new record into the WAL buffers in shared memory. If there is no space for the new record, XLogInsertRecord will have to write (move to kernel cache) a few filled WAL buffers&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;结合XLogInsertRecord函数的一段描述:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; We have now done all the preparatory work we can without holding a
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt; lock or modifying shared state. From here on, inserting the new WAL
&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 to the shared WAL buffer cache is a two&lt;span style="color:#f92672"&gt;-&lt;/span&gt;step process:
&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:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.&lt;/span&gt; Reserve the right amount of space from the WAL. The current head of
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 &lt;span style="color:#f92672"&gt;*&lt;/span&gt;	 reserved space is kept in Insert&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;CurrBytePos, and is protected 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;	 insertpos_lck.
&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:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2.&lt;/span&gt; Copy the record to the reserved WAL space. This involves finding 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;	 correct WAL buffer containing the reserved space, and copying 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;	 record in place. This can be done concurrently in multiple processes.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;XLogInsertRecord函数是用来将新的wal record到WAL buffer中的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;写入需要保留一定量的空间&lt;/li&gt;
&lt;li&gt;拷贝wal record到保留的wal空间（应指的是wal buffer中的保留空间）。&lt;strong&gt;多个进程可并行执行&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;wal record拷贝到wal buffer是可以并行执行的。这很难称为瓶颈，因为是内存拷贝还有并行。
而XLogFlush函数就不是了，XLogFlush写入的时候会一直持有一个排他LWlock。所以，在这种并发高的小事务场景中，提高wal buffer理论上效果不会太理想。&lt;/p&gt;
&lt;p&gt;至此，可以排除wal_buffers内存调整，把关注点放在IO上。再看pg_stat_activity的IO类相关等待个数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;DataFileRead	&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;DataFileExtend	&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;WALWrite		&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;WALRead			&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;insert value慢只持续了不到1分钟时间，平时没有异常。但是从平时的会话信息上看IO类的WALWrite等待基本都在&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xact_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; state_change &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; partofquery
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;72668&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;828394&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;82841&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1( &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;77215&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;342541&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;342552&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1 &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;94904&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;442309&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;442323&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1 &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;88024&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;779086&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;779311&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; table2 &lt;span style="color:#66d9ef"&gt;SET&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;103236&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;144283&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;144302&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1 &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;47342&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;192683&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;192699&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1 &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;75399&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;743023&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;743024&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; table1 &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;221993&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzluser11 &lt;span style="color:#f92672"&gt;|&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;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;46&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;184532&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;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;46&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;184541&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; WALWrite &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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; table1 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;然而检查当时IO性能，写入15M/s并不高，与其他时间段相比甚至比较低，w_await同样很低&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Device: rrqm&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s wrqm&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s r&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s w&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s rkB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s wkB&lt;span style="color:#f92672"&gt;/&lt;/span&gt;s avgrq&lt;span style="color:#f92672"&gt;-&lt;/span&gt;sz avgqu&lt;span style="color:#f92672"&gt;-&lt;/span&gt;sz await r_await w_await svctm &lt;span style="color:#f92672"&gt;%&lt;/span&gt;util
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dm&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;322&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;187.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1515.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3572.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15344.00&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22.23&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2.05&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9.39&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.18&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.15&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25.70&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;目前来看应是瞬时并发insert value小事务，对flush wal时的锁争用。可以排除以下选项:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;并发小事务，不需要&lt;a href="https://www.postgresql.org/docs/16/wal-configuration.html" target="_blank" rel="noreferrer"&gt;调整wal buffer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wal日志量不大，不需要开启&lt;a href="https://dba.stackexchange.com/questions/338319/postgres-walwrite-waits-whats-the-bottleneck" target="_blank" rel="noreferrer"&gt;日志压缩&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;FPI不多，不需要调整checkpoint&lt;/li&gt;
&lt;li&gt;IO压力不大，不需要&lt;a href="https://docs.dbmarlin.com/docs/kb/wait-events/postgresql/walwritelock/" target="_blank" rel="noreferrer"&gt;提升IO性能&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;至少可以有如下优化:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;开启数据库组提交（怕背锅可不调整，需要再测试）&lt;/li&gt;
&lt;li&gt;业务单个语句insert value语句合并提交，减少WALWriteLock锁争用&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>案例-pg中的谓词越界和prepare statement问题</title><link>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B-pg%E4%B8%AD%E7%9A%84%E8%B0%93%E8%AF%8D%E8%B6%8A%E7%95%8C%E5%92%8Cprepare-statement%E9%97%AE%E9%A2%98/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B-pg%E4%B8%AD%E7%9A%84%E8%B0%93%E8%AF%8D%E8%B6%8A%E7%95%8C%E5%92%8Cprepare-statement%E9%97%AE%E9%A2%98/</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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;案例：执行计划发生变化，plan选择了错误的索引，sql由毫秒级变成秒级。后面收集统计信息后，业务sql还是慢，最后通过删除DAILY_DATE时间索引建立(DAILY_DATE,A_ID)组合索引才解决。
疑问：&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="#%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;案例：执行计划发生变化，plan选择了错误的索引，sql由毫秒级变成秒级。后面收集统计信息后，业务sql还是慢，最后通过删除DAILY_DATE时间索引建立(DAILY_DATE,A_ID)组合索引才解决。
疑问：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;优化器为什么选择DAILY_DATE索引，而不是选择率更好的A_ID索引？&lt;/li&gt;
&lt;li&gt;收集统计信息后为什么没有效果？&lt;/li&gt;
&lt;/ol&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%9f%e8%ae%a1%e4%bf%a1%e6%81%af%e8%bf%87%e6%97%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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
&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; &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;from&lt;/span&gt; tablzl
&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; A_ID &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;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;AND&lt;/span&gt; IS_DELETE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;N&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;AND&lt;/span&gt; DAILY_DATE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; to_date(&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyyMMdd&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;and&lt;/span&gt; PARTITION_KEY &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:#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;and&lt;/span&gt; PARTITION_KEY &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;优化器选择DAILY_DATE索引而不是过滤性比较好的A_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;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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;8&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;2&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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;-&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; tablzl_p202401_DAILY_DATE_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tablzl_p202401 tablzl_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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;203&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: (DAILY_DATE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; to_date(&lt;span style="color:#e6db74"&gt;&amp;#39;20240223&amp;#39;&lt;/span&gt;::text, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyyMMdd&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((partition_key &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;202401&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (partition_key &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;202402&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((A_ID)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ID1234567890987654321&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_delete)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;N&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; tablzl_p202402_DAILY_DATE_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tablzl_p202402 tablzl_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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (DAILY_DATE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; to_date(&lt;span style="color:#e6db74"&gt;&amp;#39;20240223&amp;#39;&lt;/span&gt;::text, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyyMMdd&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((partition_key &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;202401&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (partition_key &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;202402&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((A_ID)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ID1234567890987654321&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_delete)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;N&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;ul&gt;
&lt;li&gt;对于p202401分区，走DAILY_DATE还是A_ID索引，差别不大，因为1月分区没有2月23日的数据&lt;/li&gt;
&lt;li&gt;对于p202402分区，走DAILY_DATE还是A_ID索引，差别很大。走DAILY_DATE索引，它的预估cost=3.35，rows=1，实际上有上百万的数据，跑了2秒&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;p202402的统计信息中有MCV：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pg_stats &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; tablename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;tablzl_p202402&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; attname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;DAILY_DATE&amp;#39;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;most_common_vals &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;2024&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;21&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;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&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;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;22&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;02&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;2024&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;15&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;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19&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;02&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:#ae81ff"&gt;2024&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;18&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;02&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:#ae81ff"&gt;2024&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;14&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;02&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;2024&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;07&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;02&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;2024&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;06&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;02&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:#ae81ff"&gt;2024&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:#ae81ff"&gt;02&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:#ae81ff"&gt;2024&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;03&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;02&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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;02&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;2024&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;02&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;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;31&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;02&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;2024&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;04&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;most_common_freqs &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 style="color:#ae81ff"&gt;0481&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;047766667&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0466&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0449&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0441&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043833334&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043733332&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043466665&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043133333&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043066666&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;042366665&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;041866668&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;041366667&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;041366667&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;039766666&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0394&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;039333332&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;|&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;038766667&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;03863333&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0381&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;038066667&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;037966665&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;037566666&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;036733333&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;计算MCV的总频率sum(most_common_freqs)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;0481&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;047766667&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;0466&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;0449&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;0441&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;043833334&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;043733332&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;043466665&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;043133333&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;043066666&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;042366665&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;041866668&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;041366667&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;041366667&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;039766666&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;0394&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;039333332&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;038766667&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;03863333&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;0381&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;038066667&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;037966665&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;037566666&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;036733333&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;column&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 style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;999999990&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，代表1-22日就是这个分区的所有数据（预估），23日的数据应该是0条，所以planner在预估23日的数据时rows=1，所以选择了DAILY_DATE索引。实际上23日的数据有百万条。
本质上这是一个统计信息过久造成的问题。为什么前22天没有问题而且23日没有触发自动收集呢？&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; relname,reloptions &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;tablzl&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; reloptions 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;----------------------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tablzl &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&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;show&lt;/span&gt; autovacuum_analyze_scale_factor;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; autovacuum_analyze_scale_factor 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;触发阈值默认是0.1，数据变化达到1/10的时候才会触发自动analyze。这是一个月分区，数据是每天插入和更新的，月初时1天写入200w数据，因为数据存量少，会触发多次analyze（threshold默认50可以忽略不记），而在月末时，比如23日，1天写入200w数据，不会触发analyze，因为只写了1/23。这个场景中插入后还会更新，插入200w更新200w，所以23日的数据变化是1/11左右，刚好不会触发analyze，&lt;strong&gt;这也能解释前20天运行稳定&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%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e7%bc%93%e5%ad%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为是统计信息过旧问题，手动收集统计信息理应解决这个问题，实际上收集了以后业务sql还是慢。
analyze了以后，手动explain analyze 执行计划却是正确的。
说明analyze应该是有用的，但是没有影响到业务会话。由于sql执行用的是长会话，怀疑jdbc中使用prepare statement缓存执行计划（&lt;a href="https://jenkov.com/tutorials/jdbc/preparedstatement.html#:~:text=JDBC%20PreparedStatement%201%20Creating%20a%20PreparedStatement%20Before%20you,Reusing%20a%20PreparedStatement%20...%205%20PreparedStatement%20Performance%20" target="_blank" rel="noreferrer"&gt;jdbc prepare statement&lt;/a&gt;）。
而prepare statement在pg13（rasesql 1.3）中，收集统计信息不会失效，只能通过重连会话的方式重写解析。
prepare statement会生产一个通用执行计划（generic plan），由于统计信息不准确，通用执行计划跟传参执行计划一样，可以选择错误的索引&lt;/p&gt;

&lt;h2 class="relative group"&gt;prepare statement的特性
 &lt;div id="prepare-statement的特性" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-statement%e7%9a%84%e7%89%b9%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;psql支持prepare statement，由&lt;code&gt;plan_cache_mode&lt;/code&gt;参数控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;：默认，五次机制处理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;force_custom_plan&lt;/code&gt;：永远进行硬解析，生成custom plan&lt;/li&gt;
&lt;li&gt;&lt;code&gt;force_generic_plan&lt;/code&gt;：永远使用generic plan，绑定变量&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; plan1(text,integer) &lt;span style="color:#66d9ef"&gt;AS&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; tlzl1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&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;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;month&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:#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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;11&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;deallocate&lt;/span&gt; plan1&lt;span style="color:#f92672"&gt;|&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;all&lt;/span&gt;; &lt;span style="color:#75715e"&gt;--使prepare失效，断开会话也可以&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;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_statements;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;generic plan是怎么生成的
 &lt;div id="generic-plan是怎么生成的" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#generic-plan%e6%98%af%e6%80%8e%e4%b9%88%e7%94%9f%e6%88%90%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;正常来说prepare语句跑5次是可以生成generic plan的。网上很多演示，这里就不演示正常情况了，以下是我测试出的“神奇”现象&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; tlzl1(id varchar(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;),&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; int);
&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; tlzl1 &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; md5(&lt;span style="color:#66d9ef"&gt;g&lt;/span&gt;::text),&lt;span style="color:#66d9ef"&gt;EXTRACT&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&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;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-11-30&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1(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;index&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1(&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; tlzl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--执行prepare语句
&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; plan1(text,integer) &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;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; tlzl1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&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;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;month&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:#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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;11&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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;11&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;注意这里只插入11月前的数据，12月是没有数据的。此时查12月数据可以走到month索引&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;37&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;035&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;036&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &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; Filter: ((id)::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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;170&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;058&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;5&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;551&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;=#&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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;37&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;021&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &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; Filter: ((id)::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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;168&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;046&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;5&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;488&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;=#&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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;37&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;017&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;018&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &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; Filter: ((id)::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; 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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;040&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;5&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;419&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;=#&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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;37&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;019&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;020&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &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; Filter: ((id)::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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;160&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;044&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;5&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;479&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;=#&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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_month &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;94&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;37&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;018&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;018&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (&lt;span style="color:#66d9ef"&gt;month&lt;/span&gt; &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; Filter: ((id)::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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;155&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;041&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;5&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;426&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;12&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;37&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;044&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;045&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((id)::text &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;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (&lt;span style="color:#66d9ef"&gt;month&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:#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;Rows&lt;/span&gt; Removed &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; Filter: &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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;023&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;079&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;6&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;第六次绑定了generic plan，但是并不是前五次的plan，走的是id索引。如果id的重复度再高点的话，也可以测出来绑不上generic plan的场景（未展示）。
这里就要看下源码了
&lt;code&gt;choose_custom_plan&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;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;choose_custom_plan&lt;/span&gt;(CachedPlanSource &lt;span style="color:#f92672"&gt;*&lt;/span&gt;plansource, ParamListInfo boundParams)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;/* Generate custom plans until we have done at least 5 (arbitrary) */&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;num_custom_plans &lt;span style="color:#f92672"&gt;&amp;lt;&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;		&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;	avg_custom_cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;total_custom_cost &lt;span style="color:#f92672"&gt;/&lt;/span&gt; plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;num_custom_plans;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;	 * Prefer generic plan if it&amp;#39;s less expensive than the average custom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * plan. (Because we include a charge for cost of planning 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;	 * custom-plan costs, this means the generic plan only has to be less
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * expensive than the execution cost plus replan cost of the custom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * plans.)
&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 that if generic_cost is -1 (indicating we&amp;#39;ve not yet determined
&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 generic plan cost), we&amp;#39;ll always prefer generic at this point.
&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;generic_cost &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; avg_custom_cost)
&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:#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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;只要generic plan的cost 小于 前5次的custom_cost平均值，那么就使用generic plan。
虽然5次机制众所周知，但是需要注意generic plan是怎么生成的。第5次时还没有generic plan（刚开始的时候），generic_cost=-1，会直接返回&lt;code&gt;GetCachedPlan&lt;/code&gt;中的&lt;code&gt;!customplan&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;CachedPlan &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;GetCachedPlan&lt;/span&gt;(CachedPlanSource &lt;span style="color:#f92672"&gt;*&lt;/span&gt;plansource, ParamListInfo boundParams,
&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; useResOwner, QueryEnvironment &lt;span style="color:#f92672"&gt;*&lt;/span&gt;queryEnv)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	customplan &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;choose_custom_plan&lt;/span&gt;(plansource, boundParams);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;customplan)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;CheckCachedPlan&lt;/span&gt;(plansource))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 want a generic plan, and we already have a valid one */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			plan &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;gplan;
&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;(plan&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;magic &lt;span style="color:#f92672"&gt;==&lt;/span&gt; CACHEDPLAN_MAGIC);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;/* Build a new generic plan */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			plan &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BuildCachedPlan&lt;/span&gt;(plansource, qlist, NULL, queryEnv);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Just make real sure plansource-&amp;gt;gplan is clear */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;ReleaseGenericPlan&lt;/span&gt;(plansource);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#75715e"&gt;/* Link the new generic plan into the plansource */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;gplan &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plan;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			plan&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:#75715e"&gt;/* Immediately reparent into appropriate context */&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; (plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;is_saved)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#75715e"&gt;/* saved plans all live under CacheMemoryContext */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;MemoryContextSetParent&lt;/span&gt;(plan&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;context, CacheMemoryContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				plan&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;is_saved &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;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;/* otherwise, it should be a sibling of the plansource */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;MemoryContextSetParent&lt;/span&gt;(plan&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;context,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;									 &lt;span style="color:#a6e22e"&gt;MemoryContextGetParent&lt;/span&gt;(plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;context));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 generic_cost whenever we make a new generic plan */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			plansource&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;generic_cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cached_plan_cost&lt;/span&gt;(plan, 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:#75715e"&gt;			 * If, based on the now-known value of generic_cost, we&amp;#39;d not have
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * chosen to use a generic plan, then forget it and make a custom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * plan. This is a bit of a wart but is necessary to avoid 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;			 * glitch in behavior when the custom plans are consistently big
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * winners; at some point we&amp;#39;ll experiment with a generic plan 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;			 * find it&amp;#39;s a loser, but we don&amp;#39;t want to actually execute 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;			 * plan.
&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;			customplan &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;choose_custom_plan&lt;/span&gt;(plansource, boundParams);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 choose to plan again, we need to re-copy the query_list,
&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 the planner probably scribbled on it. We can force
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;			 * BuildCachedPlan to do that by passing NIL.
&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;			qlist &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NIL;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;return&lt;/span&gt; plan;
&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;!customplan&lt;/code&gt;逻辑中，如果有generic plan直接使用，没有的话通过&lt;code&gt;BuildCachedPlan&lt;/code&gt;生成一个plan，&lt;code&gt;BuildCachedPlan&lt;/code&gt;就是生成plan的主体逻辑，通过query tree生成plan tree。
没有参数怎么办？注释已经说明，没有参数就传NULL进去，到生成plan的逻辑&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;To build a generic, parameter&lt;span style="color:#f92672"&gt;-&lt;/span&gt;value&lt;span style="color:#f92672"&gt;-&lt;/span&gt;independent plan, pass NULL &lt;span style="color:#66d9ef"&gt;for&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; boundParams. To build a custom plan, pass the actual parameter values via
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; boundParams&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;传NULL优化器更prefer什么执行计划？这部分代码逻辑有些复杂。从优化器的角度考虑，可能是有多个plan可以选择的，但总得选一个作为generic plan
而选出来那个generic plan，才可以对比前5次的plan cost。
为什么用更低cost的执行计划反复执行，没有生成想要的generic plan？
&lt;strong&gt;generic plan长什么样跟前五次的执行计划没有关系，前五次只是决定了是否绑定这个generic plan&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从优化器设计的角度来考虑，generic plan是为了减少解析时间提高sql执行效率，适合多而小的查询。问题在于generic plan本身很粗糙，postgres引进五次机制就是为了来减少generic plan本身是稀烂的可能性。
即使有五次机制，还是导致绑定的烂generic plan的原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generic plan也是plan，本身就可能烂&lt;/li&gt;
&lt;li&gt;统计信息不准确，generic plan的cost预估很低&lt;/li&gt;
&lt;li&gt;前五次的传参选择率低（或其他影响）导致custom plan cost高&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;prepare statement的失效
 &lt;div id="prepare-statement的失效" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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-statement%e7%9a%84%e5%a4%b1%e6%95%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;除了DDL、deallocate、断开会话，收集统计信息也会让prepared statement，不过这是pg14的特性。
pg13:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PostgreSQL will force re-analysis and re-planning of the statement before using it whenever database objects used in the statement have undergone definitional (DDL) changes since the previous use of the prepared statement&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;pg14:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PostgreSQL will force re-analysis and re-planning of the statement before using it whenever database objects used in the statement have undergone definitional (DDL) changes or their planner statistics have been updated since the previous use of the prepared statement&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;pg13 收集统计信息不会让prepare statement失效的测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;11&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;37&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;033&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;033&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((id)::text &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;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (&lt;span style="color:#66d9ef"&gt;month&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:#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;Rows&lt;/span&gt; Removed &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; Filter: &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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;098&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;050&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;6&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:#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_statements;
&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;statement&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; prepare_time &lt;span style="color:#f92672"&gt;|&lt;/span&gt; parameter_types &lt;span style="color:#f92672"&gt;|&lt;/span&gt; from_sql 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+-----------------------------------------------+-------------------------------+-----------------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plan1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; plan1(text,integer) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#f92672"&gt;+|&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;02&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;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;966733&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;text,integer&lt;span style="color:#960050;background-color:#1e0010"&gt;}&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:#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; tlzl1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&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;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;month&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:#ae81ff"&gt;2&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:#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;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt; tlzl1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ANALYZE&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; pg_prepared_statements;
&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;statement&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; prepare_time &lt;span style="color:#f92672"&gt;|&lt;/span&gt; parameter_types &lt;span style="color:#f92672"&gt;|&lt;/span&gt; from_sql 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-------+-----------------------------------------------+-------------------------------+-----------------+----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plan1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PREPARE&lt;/span&gt; plan1(text,integer) &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#f92672"&gt;+|&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;02&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;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;966733&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;text,integer&lt;span style="color:#960050;background-color:#1e0010"&gt;}&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:#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; tlzl1 &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&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;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;month&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:#ae81ff"&gt;2&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:#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;=&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;EXECUTE&lt;/span&gt; plan1(&lt;span style="color:#e6db74"&gt;&amp;#39;256ac66bb53d31bc6124294238d6410c&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;11&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tlzl1 (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;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;37&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;051&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;052&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((id)::text &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;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (&lt;span style="color:#66d9ef"&gt;month&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:#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;Rows&lt;/span&gt; Removed &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; Filter: &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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;022&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;098&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;6&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;jdbc的prepare statement
 &lt;div id="jdbc的prepare-statement" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#jdbc%e7%9a%84prepare-statement" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;prepare statement不是PG的独有功能，一些数据库也有相关的预解析特性，比如oracle也可以实现类似的功能。
&lt;a href="https://jenkov.com/tutorials/jdbc/preparedstatement.html#:~:text=JDBC%20PreparedStatement%201%20Creating%20a%20PreparedStatement%20Before%20you,Reusing%20a%20PreparedStatement%20...%205%20PreparedStatement%20Performance%20" target="_blank" rel="noreferrer"&gt;jdbc&lt;/a&gt;自身也可以调用数据库的预解析接口，直接显示使用 prepare statement。
jdbc参考配置：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;String &lt;span style="color:#66d9ef"&gt;sql&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;select * from people where id=?&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;PreparedStatement preparedStatement &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;connection&lt;/span&gt;.prepareStatement(&lt;span style="color:#66d9ef"&gt;sql&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%bb%ba%e8%ae%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;调小表级的&lt;code&gt;autovacuum_analyze_scale_factor=0.02&lt;/code&gt;（why 0.02？0.02&amp;lt;1/31)。因为是边写边查，手动收集不太好定时间，调小&lt;code&gt;autovacuum_analyze_scale_factor&lt;/code&gt;只能减缓这个问题。&lt;/li&gt;
&lt;li&gt;考虑去掉jdbc中的prepare设置，或者设置&lt;code&gt;force_custom_plan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调整sql逻辑&lt;/li&gt;
&lt;li&gt;调整索引。4.1删除不必要的时间索引；4.2将越界后走的索引重建为包含id字段的组合索引（一个不错的建议）。&lt;/li&gt;
&lt;li&gt;应急流程：统计信息收集后业务未恢复的情况，确认手动explain执行计划改变的情况下，可以考虑杀会话(13以前)。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后，谓词越界问题基本上在所有数据库中都有，特别是在时间字段上。现有手段其实没有一个比较简单又能完美解决的办法，oracle的SPM好感度又+1&amp;hellip;&lt;/p&gt;</content:encoded></item><item><title>案例：逻辑复制把checkpoint、walsender、backup全部卡死</title><link>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%8A%8Acheckpointwalsenderbackup%E5%85%A8%E9%83%A8%E5%8D%A1%E6%AD%BB/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%A1%88%E4%BE%8B%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%8A%8Acheckpointwalsenderbackup%E5%85%A8%E9%83%A8%E5%8D%A1%E6%AD%BB/</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_start_backup()被checkpoint进程阻塞，checkpoint被逻辑复制walsender进程阻塞。业务虽然还在继续运行，但是备份、checkpoint、逻辑复制全部hang死。&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_start_backup()被checkpoint进程阻塞，checkpoint被逻辑复制walsender进程阻塞。业务虽然还在继续运行，但是备份、checkpoint、逻辑复制全部hang死。&lt;/p&gt;
&lt;p&gt;pg_stat_activity 中有两个明显异常的等待事件：&lt;code&gt;replication_slot_io&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[postgres&lt;span style="color:#f92672"&gt;@&lt;/span&gt;hostlzl:&lt;span style="color:#ae81ff"&gt;6666&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres][&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;08&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&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_stat_activity &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; pid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;173038&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;datid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17630&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; lzldb
&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;173038&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;35157&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; repuser
&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; PostgreSQL JDBC Driver
&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;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;75&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;58&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 style="color:#66d9ef"&gt;null&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;37623&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;2024&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;02&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;75022&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;xact_start &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;query_start &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;state_change &lt;span style="color:#f92672"&gt;|&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;04&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;11&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;764475&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;wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replication_slot_io
&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; active
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_xid &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;backend_xmin &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;query &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; walsender
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;6&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;658&lt;/span&gt; ms
&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;hostlzl:&lt;span style="color:#ae81ff"&gt;6666&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;postgres][&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;08&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;34&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_stat_activity &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; pid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12729&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;gx
&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;datid &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;datname &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;pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12729&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:#66d9ef"&gt;null&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; [&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;application_name &lt;span style="color:#f92672"&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:#66d9ef"&gt;null&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 style="color:#66d9ef"&gt;null&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:#66d9ef"&gt;null&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;2024&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;02&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;03&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;343116&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;xact_start &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;query_start &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;state_change &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;wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LWLock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replication_slot_io
&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; [&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;backend_xid &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;backend_xmin &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;query &lt;span style="color:#f92672"&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;backend_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; checkpointer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;一个是walsender进程，一个是checkpointer进程。都是4月2日启动的进程，直接查看4月2日walsender 173038的日志：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--repuser log
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:40:07.750 CST,,,173038,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:37623&amp;#34;&lt;/span&gt;,660b7e17.2a3ee,1,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,2024-04-02 11:40:07 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;connection received: host=30.88.75.58 port=37623&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:40:07.756 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,173038,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:37623&amp;#34;&lt;/span&gt;,660b7e17.2a3ee,2,&lt;span style="color:#e6db74"&gt;&amp;#34;authentication&amp;#34;&lt;/span&gt;,2024-04-02 11:40:07 CST,32/30,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;replication connection authorized: user=repuser&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:40:07.765 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,173038,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:37623&amp;#34;&lt;/span&gt;,660b7e17.2a3ee,3,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:40:07 CST,32/0,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;starting logical decoding for slot &amp;#34;&amp;#34;pg_lzldb_lzldb_ora_pgdb_pgdb&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Streaming transactions committing after 4263/42E6EF88, reading WAL from 4263/41DAEBD0.&amp;#34;&lt;/span&gt;,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:40:07.765 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,173038,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:37623&amp;#34;&lt;/span&gt;,660b7e17.2a3ee,4,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:40:07 CST,32/0,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;logical decoding found consistent point at 4263/41DAEBD0&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;There are no running transactions.&amp;#34;&lt;/span&gt;,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&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;173038这个walsender进程只能看到start启动链路信息，后面这个walsender再也没有输出过日志，很有可能从那个时候起开始hang了。
不过再往前翻一点，还可以看到相同复制链路的walsender信息（walsender进程号不同，slot name相同）：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--84918 之前的启动日志
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:30:07.498 CST,,,84918,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:54898&amp;#34;&lt;/span&gt;,660b7bbf.14bb6,1,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,2024-04-02 11:30:07 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;connection received: host=30.88.75.58 port=54898&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:30:07.504 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,84918,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:54898&amp;#34;&lt;/span&gt;,660b7bbf.14bb6,2,&lt;span style="color:#e6db74"&gt;&amp;#34;authentication&amp;#34;&lt;/span&gt;,2024-04-02 11:30:07 CST,30/3,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;replication connection authorized: user=repuser&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:30:07.514 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,84918,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:54898&amp;#34;&lt;/span&gt;,660b7bbf.14bb6,3,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:30:07 CST,30/0,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;starting logical decoding for slot &amp;#34;&amp;#34;pg_lzldb_lzldb_ora_pgdb_pgdb&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Streaming transactions committing after 4263/41DADE38, reading WAL from 4263/358F1340.&amp;#34;&lt;/span&gt;,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:30:07.516 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,84918,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:54898&amp;#34;&lt;/span&gt;,660b7bbf.14bb6,4,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:30:07 CST,30/0,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;logical decoding found consistent point at 4263/358F1340&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;There are no running transactions.&amp;#34;&lt;/span&gt;,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&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;2024-04-02 11:36:07.061 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,86630,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:45227&amp;#34;&lt;/span&gt;,660b7bca.15266,5,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:30:18 CST,30/0,0,ERROR,XX000,&lt;span style="color:#e6db74"&gt;&amp;#34;could not write to file &amp;#34;&amp;#34;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;#34;&amp;#34;: Cannot allocate memory&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:36:40.151 CST,&lt;span style="color:#e6db74"&gt;&amp;#34;repuser&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,86630,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.75.58:45227&amp;#34;&lt;/span&gt;,660b7bca.15266,6,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;,2024-04-02 11:30:18 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;disconnection: session time: 0:06:21.760 user=repuser database=lzldb host=30.88.75.58 port=45227&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&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;这个复制槽在11:30:07也启动过一次，并且过了6分钟后，因为内存打满导致写入&lt;code&gt;state.tmp&lt;/code&gt;失败。
同样的，上面查出来的checkpoint进程12729，也报了相同的state.tmp文件错误&lt;code&gt;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;quot;&amp;quot;: File exists&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;--checkpoint log
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:36:39.925 CST,,,12729,,660b7a17.31b9,4,,2024-04-02 11:23:03 CST,,0,LOG,58P02,&lt;span style="color:#e6db74"&gt;&amp;#34;could not create file &amp;#34;&amp;#34;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;#34;&amp;#34;: File exists&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:36:40.151 CST,,,12729,,660b7a17.31b9,5,,2024-04-02 11:23:03 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpoint complete: wrote 334 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.108 s, sync=0.082 s, total=217.083 s; sync files=139, longest=0.004 s, average=0.000 s; distance=2295 kB, estimate=2295 kB&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-02 11:48:03.414 CST,,,12729,,660b7a17.31b9,6,,2024-04-02 11:23:03 CST,,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;checkpoint starting: time&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&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;checkpoint此后再也没有出现过日志输出，看起来跟walsender一样，hang住了。&lt;/p&gt;
&lt;p&gt;通过搜索&lt;code&gt;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;quot;&amp;quot;: File exists&amp;quot;&lt;/code&gt;可以快速又简单的找到社区邮件：&lt;a href="https://www.postgresql.org/message-id/14b3454f-2d68-c637-68e4-2b42ff976168%40postgrespro.ru" target="_blank" rel="noreferrer"&gt;https://www.postgresql.org/message-id/14b3454f-2d68-c637-68e4-2b42ff976168%40postgrespro.ru&lt;/a&gt;
它真正的修复版本是&lt;a href="https://www.postgresql.org/docs/release/12.3/" target="_blank" rel="noreferrer"&gt;PG12.3&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Ensure that a replication slot&amp;rsquo;s io_in_progress_lock is released in failure code paths (Pavan Deolasee)
This could result in a walsender later becoming stuck waiting for the lock.&lt;/p&gt;
&lt;/blockquote&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%b7%b1%e5%85%a5%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;虽然找到了bug，但其实很多问题没有搞清楚：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;walsender和checkpoints为什么hang住了？&lt;/li&gt;
&lt;li&gt;walsender和checkpoints是谁阻塞了谁？&lt;/li&gt;
&lt;li&gt;怎么触发的？&lt;/li&gt;
&lt;li&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="#%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;当前版本为11.5。&lt;/p&gt;
&lt;p&gt;walsender和checkpointer两个进程的的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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@hostlzl:lzldb:6666: /pg/pg6666/data/pg_log&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pstack &lt;span style="color:#ae81ff"&gt;173038&lt;/span&gt; &lt;span style="color:#75715e"&gt;##walsender&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#0 0x00002b9eec171a0b in do_futex_wait.constprop.1 () from /lib64/libpthread.so.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;#1 0x00002b9eec171a9f in __new_sem_wait_slow.constprop.0 () from /lib64/libpthread.so.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;#2 0x00002b9eec171b3b in sem_wait@@GLIBC_2.2.5 () from /lib64/libpthread.so.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;#3 0x00000000006b2512 in PGSemaphoreLock (sema=0x2b9ef5fdb0b8) at pg_sema.c:316&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 0x000000000071e94c in LWLockAcquire (lock=lock@entry=0x2babd8cee5b8, mode=mode@entry=LW_EXCLUSIVE) at lwlock.c:1243&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 0x00000000006ef7cb in SaveSlotToPath (slot=0x2babd8cee500, dir=dir@entry=0x7ffcaffd79f0 &amp;#34;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb&amp;#34;, elevel=elevel@entry=20) at slot.c:1249&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 0x00000000006f0515 in ReplicationSlotSave () at slot.c:653&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 0x00000000006d75d8 in LogicalConfirmReceivedLocation (lsn=&amp;lt;optimized out&amp;gt;) at logical.c:1049&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 0x00000000006d774d in LogicalIncreaseXminForSlot (current_lsn=current_lsn@entry=72994075200640, xmin=xmin@entry=1241611955) at logical.c:914&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 0x00000000006e0fb3 in SnapBuildProcessRunningXacts (builder=builder@entry=0x23146c0, lsn=72994075200640, running=running@entry=0x22e8978) at snapbuild.c:1146&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#10 0x00000000006d484c in DecodeStandbyOp (buf=0x7ffcaffd7eb0, buf=0x7ffcaffd7eb0, ctx=0x2209820) at decode.c:318&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#11 LogicalDecodingProcessRecord (ctx=0x2209820, record=&amp;lt;optimized out&amp;gt;) at decode.c:121&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#12 0x00000000006e50e0 in XLogSendLogical () at walsender.c:2799&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#13 0x00000000006e7122 in WalSndLoop (send_data=send_data@entry=0x6e5080 &amp;lt;XLogSendLogical&amp;gt;) at walsender.c:2162&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#14 0x00000000006e7d91 in StartLogicalReplication (cmd=0x22eedd8) at walsender.c:1109&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#15 exec_replication_command (cmd_string=cmd_string@entry=0x2210c48 &amp;#34;START_REPLICATION SLOT pg_lzldb_lzldb_ora_pgdb_pgdb LOGICAL 4263/42E6EF88 (\&amp;#34;add-tables\&amp;#34; &amp;#39;public.acr_finance_coa_partition_17_01,public.acr_finance_coa_partition_17_02,public.acr_finance_coa_part&amp;#34;...) at walsender.c:1541&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#16 0x000000000072c899 in PostgresMain (argc=&amp;lt;optimized out&amp;gt;, argv=argv@entry=0x2216f78, dbname=0x2216c98 &amp;#34;lzldb&amp;#34;, username=&amp;lt;optimized out&amp;gt;) at postgres.c:4178&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#17 0x000000000047e481 in BackendRun (port=0x220eda0) at postmaster.c:4358&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#18 BackendStartup (port=0x220eda0) at postmaster.c:4030&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#19 ServerLoop () at postmaster.c:1707&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#20 0x00000000006c4359 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x21dbe90) at postmaster.c:1380&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#21 0x000000000047eefb in main (argc=3, argv=0x21dbe90) at main.c:228&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;postgres@hostlzl:lzldb:6666: /pg/pg6666/data/pg_wal&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pstack &lt;span style="color:#ae81ff"&gt;12729&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;&lt;span style="color:#75715e"&gt;#0 0x00002b9eec171a0b in do_futex_wait.constprop.1 () from /lib64/libpthread.so.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;#1 0x00002b9eec171a9f in __new_sem_wait_slow.constprop.0 () from /lib64/libpthread.so.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;#2 0x00002b9eec171b3b in sem_wait@@GLIBC_2.2.5 () from /lib64/libpthread.so.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;#3 0x00000000006b2512 in PGSemaphoreLock (sema=0x2b9ef5fdcd38) at pg_sema.c:316&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 0x000000000071e94c in LWLockAcquire (lock=lock@entry=0x2babd8cee5b8, mode=mode@entry=LW_EXCLUSIVE) at lwlock.c:1243&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 0x00000000006ef7cb in SaveSlotToPath (slot=slot@entry=0x2babd8cee500, dir=dir@entry=0x7ffcaffd6ee0 &amp;#34;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb&amp;#34;, elevel=elevel@entry=15) at slot.c:1249&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 0x00000000006f11a7 in CheckPointReplicationSlots () at slot.c:1100&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 0x00000000004f674f in CheckPointGuts (checkPointRedo=72994093982360, flags=flags@entry=128) at xlog.c:9146&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 0x00000000004fcc77 in CreateCheckPoint (flags=flags@entry=128) at xlog.c:8937&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 0x00000000006b8312 in CheckpointerMain () at checkpointer.c:491&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#10 0x000000000050ba15 in AuxiliaryProcessMain (argc=argc@entry=2, argv=argv@entry=0x7ffcaffd7540) at bootstrap.c:451&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#11 0x00000000006c1cb9 in StartChildProcess (type=CheckpointerProcess) at postmaster.c:5337&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#12 0x00000000006c2f5a in reaper (postgres_signal_arg=&amp;lt;optimized out&amp;gt;) at postmaster.c:2867&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#13 &amp;lt;signal handler called&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#14 0x00002b9eed5ba783 in __select_nocancel () from /lib64/libc.so.6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#15 0x000000000047db38 in ServerLoop () at postmaster.c:1671&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#16 0x00000000006c4359 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x21dbe90) at postmaster.c:1380&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#17 0x000000000047eefb in main (argc=3, argv=0x21dbe90) at main.c:228&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;LWLockAcquire&lt;/code&gt;这行的堆栈，walsender和checkpointer都有这样的进栈，并且他们俩都以排他模式申请了同一个LWLOCK地址：&lt;code&gt;lock=lock@entry=0x2babd8cee5b8, mode=mode@entry=LW_EXCLUSIVE&lt;/code&gt;，进入无限期的等待···
&lt;code&gt;LWLockAcquire&lt;/code&gt;的上一个堆栈函数便是&lt;code&gt;SaveSlotToPath&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;src/backend/replication/slot.c&lt;/code&gt;中找到关键问题函数源码&lt;code&gt;SaveSlotToPath&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;//SaveSlotToPath用于存储slot的状态
&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;SaveSlotToPath&lt;/span&gt;(ReplicationSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;slot, &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;dir, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; elevel)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{	&lt;span style="color:#75715e"&gt;//11.5代码
&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;		tmppath[MAXPGPATH];
&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;		path[MAXPGPATH];
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ReplicationSlotOnDisk cp;
&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;		was_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;/* and don&amp;#39;t do anything if there&amp;#39;s nothing to write */&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;was_dirty)
&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 style="color:#75715e"&gt;//函数开头获得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;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;io_in_progress_lock, 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;//注意fd的逻辑，报错与第二次walsender报错一致
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OpenTransientFile&lt;/span&gt;(tmppath, O_CREAT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_EXCL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_WRONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; PG_BINARY);
&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; (fd &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:#a6e22e"&gt;ereport&lt;/span&gt;(elevel,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;errcode_for_file_access&lt;/span&gt;(),
&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;could not create file &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;: %m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						tmppath)));
&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;//写入fd文件的逻辑，报错与首次walsender报错一致
&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;write&lt;/span&gt;(fd, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;cp, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(cp))) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(cp))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;			save_errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; errno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;pgstat_report_wait_end&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;CloseTransientFile&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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 write didn&amp;#39;t set errno, assume problem is no disk space */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; save_errno &lt;span style="color:#f92672"&gt;?&lt;/span&gt; save_errno : ENOSPC;
&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;(elevel,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;errcode_for_file_access&lt;/span&gt;(),
&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;could not write to file &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;: %m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						tmppath)));
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;LWLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;io_in_progress_lock);	&lt;span style="color:#75715e"&gt;//函数最后释放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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SaveSlotToPath&lt;/code&gt;函数上来就获取&lt;code&gt;LWLockAcquire&lt;/code&gt;，传入slot地址，命名跟等待事件非常类似：&lt;code&gt;io_in_progress_lock&lt;/code&gt;&amp;lt;-&amp;gt;&lt;code&gt; replication_slot_io&lt;/code&gt;，以&lt;code&gt;LW_EXCLUSIVE&lt;/code&gt;模式申请LWLOCK。
在&lt;code&gt;SaveSlotToPath&lt;/code&gt;函数最后有&lt;code&gt;LWLockRelease&lt;/code&gt;释放LWLOCK。
&lt;strong&gt;但是，在所有if判断中，没有任何LWLockRelease，直接return&lt;/strong&gt;！！！&lt;/p&gt;
&lt;p&gt;而pg日志中的输出就是“could not create file” tmppath，说明代码就是走到了以上两个if逻辑里，也就是&lt;strong&gt;写入state.tmp失败&lt;/strong&gt;和&lt;strong&gt;创建state.tmp失败&lt;/strong&gt;的if逻辑中。&lt;/p&gt;
&lt;p&gt;联系pglog中的报错顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;11:36:07：逻辑复制首次报错&amp;quot;could not write to file &amp;ldquo;&amp;ldquo;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;rdquo;，复制链路挂掉&lt;/li&gt;
&lt;li&gt;11:36:39：checkpointer进程报错&amp;quot;could not create file &amp;ldquo;&amp;ldquo;pg_replslot/pg_lzldb_lzldb_ora_pgdb_pgdb/state.tmp&amp;rdquo;，并于1秒后“complete”，写入0个脏块，0条wal&lt;/li&gt;
&lt;li&gt;11:40:07：逻辑复制再次启动，启动后再无输出&lt;/li&gt;
&lt;li&gt;11:48:03：checkpointer进程再次触发start，后续再无输出，后续再无输出&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上面有两个逻辑复制和两个checkpointer的日志输出，这里要注意一个很重要的信息：第一次逻辑复制和第二次逻辑复制归属于&lt;em&gt;不同的&lt;/em&gt;walsender进程；第一次checkpoint和第二次checkpoint信息归属于&lt;em&gt;相同的&lt;/em&gt;checkpointer进程。&lt;/p&gt;
&lt;p&gt;从以上信息总结出故障原理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;逻辑复制因内存问题，写入state.tmp失败，留下一个残存的state.tmp文件&lt;/li&gt;
&lt;li&gt;checkpointer进程因残存的state.tmp文件，在&lt;code&gt;SaveSlotToPath&lt;/code&gt;函数中，以排他模式获得LWLock后进入&lt;code&gt;if (fd &amp;lt; 0)&lt;/code&gt;判断，不释放LWLock直接return&lt;/li&gt;
&lt;li&gt;逻辑复制再次启动，walsender进程在&lt;code&gt;SaveSlotToPath&lt;/code&gt;函数开头申请LWLock，开始无限期等待&lt;/li&gt;
&lt;li&gt;checkpointer进程触发start checkpoint，checkpointer进程在&lt;code&gt;SaveSlotToPath&lt;/code&gt;函数开头申请LWLock，开始无限期等待&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;故障原理理清后答案自然就很清楚：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;walsender和checkpointer为什么hang住了？如上故障原理分析。残存的state.tmp，checkpointer持有LWLock未释放，walsender和checkpointer无限等待。&lt;/li&gt;
&lt;li&gt;walsender和checkpointer是谁阻塞了谁？checkpointer阻塞walsender&lt;/li&gt;
&lt;li&gt;怎么触发的？前一个walsender进程因为内存打满写了state.tmp未清理&lt;/li&gt;
&lt;li&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%8d%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;pg逻辑复制知识可参考&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171267312516800182785061%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=171267312516800182785061&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-129291207-null-null.nonecase&amp;amp;utm_term=%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg内功修炼：逻辑复制&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_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;pg_recvlogical &lt;span style="color:#f92672"&gt;-&lt;/span&gt;h &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 style="color:#f92672"&gt;-&lt;/span&gt;p &lt;span style="color:#ae81ff"&gt;5558&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#f92672"&gt;-&lt;/span&gt;U lzl &lt;span style="color:#75715e"&gt;--slot=logical_test --start -f recv.sql &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;复制槽和逻辑复制链路就OK了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; pid,usename,xact_start,state_change,wait_event,&lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;,query &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_activity &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idle&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; xact_start ;
&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; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xact_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; state_change &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; query 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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:#ae81ff"&gt;59916&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; postgres &lt;span style="color:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;015534&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;2024&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;08&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;015545&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:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pid,usename,xact_start,state_change,wait_event,&lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;,query &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_activity wher
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;e &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idle&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; xact_start ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;59791&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:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;566112&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; WalSenderWaitForWAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; pg_catalog.set_config(&lt;span style="color:#e6db74"&gt;&amp;#39;search_path&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&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;postgres&lt;span style="color:#f92672"&gt;=#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; pid,usename,application_name,backend_start,&lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;,pg_walfile_name_offset(sent_lsn) sentoffset,pg_walfile_name_offset(write_lsn) writeoffset,pg_walfile_name_offset(flush_lsn) flushoffset &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; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; application_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; backend_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; sentoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; writeoffset &lt;span style="color:#f92672"&gt;|&lt;/span&gt; flushoffset 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;59791&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_recvlogical &lt;span style="color:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;56364&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; streaming &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000010000000000000001&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6612032&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000010000000000000001&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6612032&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;000000010000000000000001&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6612032&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为是state.tmp文件引起的，直接在pg_replslot下面touch&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;testhost logical_test]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pgdata&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzl&lt;span style="color:#f92672"&gt;/&lt;/span&gt;data11&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pg_replslot&lt;span style="color:#f92672"&gt;/&lt;/span&gt;logical_test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;pg_recvlogical立马报错：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_recvlogical: unexpected termination &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; replication stream: ERROR: could &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; file &lt;span style="color:#e6db74"&gt;&amp;#34;pg_replslot/logical_test/state.tmp&amp;#34;&lt;/span&gt;: File &lt;span style="color:#66d9ef"&gt;exists&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;手动执行checkpoint也会hang住&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;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:#75715e"&gt;--hang&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在看下walsender和会话的状态：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;=&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_stat_activity ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; datid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; datname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usesysid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; application_name &lt;span style="color:#f92672"&gt;|&lt;/span&gt; client_addr &lt;span style="color:#f92672"&gt;|&lt;/span&gt; client_hostname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; client_port &lt;span style="color:#f92672"&gt;|&lt;/span&gt; backend_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xact_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; query_start 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; state_change &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; backend_xid &lt;span style="color:#f92672"&gt;|&lt;/span&gt; backend_xmin &lt;span style="color:#f92672"&gt;|&lt;/span&gt; query &lt;span style="color:#f92672"&gt;|&lt;/span&gt; backend_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;&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Activity &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LogicalLauncherMain &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; logical replication launcher
&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;2024&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;08&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;058523&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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:#66d9ef"&gt;checkpoint&lt;/span&gt;; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; client backend
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;16384&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldb &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;77638&lt;/span&gt; &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; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; pg_recvlogical &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 style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56928&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;495833&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:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;497754&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:#f92672"&gt;|&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;04&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:#ae81ff"&gt;21&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;498329&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; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replication_slot_io &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &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:#66d9ef"&gt;SELECT&lt;/span&gt; pg_catalog.set_config(&lt;span style="color:#e6db74"&gt;&amp;#39;search_path&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; walsender
&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; LWLock &lt;span style="color:#f92672"&gt;|&lt;/span&gt; replication_slot_io &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; checkpointer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;完美复现2个replication_slot_io 等待事件&lt;/p&gt;

&lt;h3 class="relative group"&gt;PG12.3的代码已优化
 &lt;div id="pg123的代码已优化" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#pg123%e7%9a%84%e4%bb%a3%e7%a0%81%e5%b7%b2%e4%bc%98%e5%8c%96" 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:#75715e"&gt;//这里贴的是15.3，比12.3多一段save_errno
&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;SaveSlotToPath&lt;/span&gt;(ReplicationSlot &lt;span style="color:#f92672"&gt;*&lt;/span&gt;slot, &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;dir, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; elevel)
&lt;/span&gt;&lt;/span&gt;&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 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OpenTransientFile&lt;/span&gt;(tmppath, O_CREAT &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_EXCL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; O_WRONLY &lt;span style="color:#f92672"&gt;|&lt;/span&gt; PG_BINARY);
&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; (fd &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 an ERROR, then release the lock before returning. In case
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;		 * of an ERROR, the error recovery path automatically releases 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;		 * lock, but no harm in explicitly releasing even in that case. Note
&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 LWLockRelease() could affect errno.
&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;			save_errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; errno;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;io_in_progress_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		errno &lt;span style="color:#f92672"&gt;=&lt;/span&gt; save_errno;
&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;(elevel,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;errcode_for_file_access&lt;/span&gt;(),
&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;could not create file &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;: %m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						tmppath)));
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;LWLockRelease&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;slot&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;io_in_progress_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;strong&gt;每一个 if中&lt;/strong&gt;，在都会先运行LWLockRelease，然后再return。这样就不会某些场景下LWLock不释放的逻辑漏洞了，代码明显更为健壮。&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%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为state.tmp文件只是诱因，LWLOCK已经持有了，删除state.tmp不会解决这个问题。
因为真正持有LW_LOCK的人是checkpointer，所以重启复制链路或者kill下游都是也是没有用的。
因为是checkpointer进程不能直接kill，目前这个状态除了重启没有好的解决办法，而且只有&lt;strong&gt;强制重启&lt;/strong&gt;进行实例恢复，正常关库因为checkpoint阻塞是关不了的···
最后，终极解决办法当然是升级到PG12.3以上。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;（另外，我也试了下gdb调用LWLockRelease（LWLock的地址pstack已经输出了），直接把测试环境库搞挂了，所以就不推荐gdb了）&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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;PG在近期的版本中最为重要的特性提升之一就是逻辑复制，早期的PG的逻辑复制确实是存在很多问题，坑多。PG这种&lt;a href="https://blog.csdn.net/qq_40687433/article/details/136405862?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;大包大揽的逻辑复制思路&lt;/a&gt;很有技术创新的精神，而且也能看到社区孜孜不倦地对逻辑复制的完善和加强，几乎每个小版本都能搜到逻辑复制的许多更新。这个案例就是一个现实的例子，逻辑复制的代码明显越来越健壮。
逻辑复制的知识点其实挺多的，最后推荐一波之前的文章：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/129291207?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171267312516800182785061%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=171267312516800182785061&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-129291207-null-null.nonecase&amp;amp;utm_term=%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg内功修炼：逻辑复制&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>从很慢的唯一索引扫描到索引膨胀</title><link>https://lastdba.com/2024/08/12/%E4%BB%8E%E5%BE%88%E6%85%A2%E7%9A%84%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%E6%89%AB%E6%8F%8F%E5%88%B0%E7%B4%A2%E5%BC%95%E8%86%A8%E8%83%80/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E4%BB%8E%E5%BE%88%E6%85%A2%E7%9A%84%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%E6%89%AB%E6%8F%8F%E5%88%B0%E7%B4%A2%E5%BC%95%E8%86%A8%E8%83%80/</guid><description>&lt;h2 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="#%e8%b5%b0%e4%b8%bb%e9%94%ae%e7%9a%84sql%e6%98%af%e6%80%8e%e4%b9%88%e8%ae%bf%e9%97%ae%e4%ba%86%e5%a4%9a%e4%b8%aa%e6%95%b0%e6%8d%ae%e9%a1%b5%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;书接上回 ：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/137248306?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;长事务、表膨胀、limit问题的一个经典案例&lt;/a&gt;，这篇文章有一个点没有说的很仔细：
为什么一个走主键的SQL会产生那么多shared hit？
为什么索引膨胀会导致访问多个数据页呢？页内的HOT只要一个数据页访问，页外的数据难道不可以通过访问对应的那一条索引条目来定位？
这跟索引的版本管理有关系了，其实索引还是有一点版本信息的，但不多。先温故一下pg的btree索引结构



&lt;img src="https://lastdba.com/img/csdn/0ed8fa95f2df.png" alt="在这里插入图片描述" /&gt;（https://en.wikibooks.org/wiki/PostgreSQL/Index_Btree）
这个pg btree wiki图其实没有解释死元组和死索引条目的访问方式，它没有版本信息。目前不用硬理解这个结构的所有细节，知道有这么个btree结构就行。&lt;/p&gt;</description><content:encoded>
&lt;h2 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="#%e8%b5%b0%e4%b8%bb%e9%94%ae%e7%9a%84sql%e6%98%af%e6%80%8e%e4%b9%88%e8%ae%bf%e9%97%ae%e4%ba%86%e5%a4%9a%e4%b8%aa%e6%95%b0%e6%8d%ae%e9%a1%b5%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;书接上回 ：&lt;a href="https://blog.csdn.net/qq_40687433/article/details/137248306?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;长事务、表膨胀、limit问题的一个经典案例&lt;/a&gt;，这篇文章有一个点没有说的很仔细：
为什么一个走主键的SQL会产生那么多shared hit？
为什么索引膨胀会导致访问多个数据页呢？页内的HOT只要一个数据页访问，页外的数据难道不可以通过访问对应的那一条索引条目来定位？
这跟索引的版本管理有关系了，其实索引还是有一点版本信息的，但不多。先温故一下pg的btree索引结构



&lt;img src="https://lastdba.com/img/csdn/0ed8fa95f2df.png" alt="在这里插入图片描述" /&gt;（https://en.wikibooks.org/wiki/PostgreSQL/Index_Btree）
这个pg btree wiki图其实没有解释死元组和死索引条目的访问方式，它没有版本信息。目前不用硬理解这个结构的所有细节，知道有这么个btree结构就行。&lt;/p&gt;
&lt;p&gt;为了搞清楚btree的版本访问问题，我们来做个测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; tab1(a bigserial,b char(&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;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_tab1_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab1(a);
&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; tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (autovacuum_enabled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab1 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;storage&lt;/span&gt; PLAIN; &lt;span style="color:#75715e"&gt;--关闭toast&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:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; tab1(b) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;zzzzzzzzz&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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;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;tab1&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;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;111875&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&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--查看索引页上索引条目信息（注意索引0号页是meta页，没有数据）
&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; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;仅插入一条数据，数据页page 0上只有1个元组，索引页page 1上只有一个条目指向ctid(0,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;=&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;xxxxxxx&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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;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;tab1&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;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;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;111875&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111876&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_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;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;111876&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&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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;更新一条数据，数据页page 0上有2个元组，活着的只有ctid(0,2)，lp=1的元组是“死”的了，但是lp_flags还是“NORMAL”的！索引页page 1上只有一个条目指向ctid(0,1)，也就是“死”元组。这个就是HOT的原理，块内更新数据时不会更新索引条目，索引通过指向死元组的ctid链去找到真正活着的数据元组。&lt;/p&gt;
&lt;p&gt;循环更新10次，造成2个数据页和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;&lt;span style="color:#66d9ef"&gt;DO&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;FOR&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; LOOP
&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; tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;md5(i::text);
&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; LOOP; 
&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:#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;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;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;tab1&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;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_flag
&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;&lt;span style="color:#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;|&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:#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&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;111876&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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&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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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_COMBOCID,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&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;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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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_HASVARWIDTH,HEAP_COMBOCID,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&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;5&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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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_HASVARWIDTH,HEAP_COMBOCID,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&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;7&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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_HASVARWIDTH,HEAP_COMBOCID,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&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:#ae81ff"&gt;1&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_COMBOCID,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;7&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;--第二个数据页
&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; 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;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;tab1&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&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;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;1&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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_COMBOCID,HEAP_UPDATED,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;1&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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_COMBOCID,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&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:#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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_COMBOCID,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&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:#ae81ff"&gt;5&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;111877&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;HEAP_HASVARWIDTH,HEAP_COMBOCID,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&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:#ae81ff"&gt;5&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;111877&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;9&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;第一个数据页page 0通过LP_REDIRECT的状态可以直接判断当前数据页肯定有HOT，此时的lp1上是没有任何其他任何信息的，甚至连ctid，data、infomask都没有。无法这条lp找到最终的数据，对于索引第一个个条目来说，访问到ctid(0,1)就可以了，这个数据页里面没有想要的数据行。
但是数据页2是有没有LP_REDIRECT的，索引可以通过找到ctid(1,0)的ctid链，找到页内的活元组(1,5)。
源码对line pointer状态的解释：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;/* unused (should always 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_NORMAL		1		&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* used (should always have lp_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 (should have lp_len=0)，其实不是HOT，而是页外的redirect标识 */&lt;/span&gt;&lt;span style="color:#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, may or may not have storage */&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;//对LP_REDIRECT的解释
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Redirecting line 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;	A line pointer that points to another line pointer and has no
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	associated tuple. It has the special lp_flags state LP_REDIRECT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	and lp_off is the OffsetNumber of the line pointer it links to.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	This is used when a root tuple becomes dead but we cannot prune
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	the line pointer because there are non&lt;span style="color:#f92672"&gt;-&lt;/span&gt;dead heap&lt;span style="color:#f92672"&gt;-&lt;/span&gt;only tuples
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	further down the chain.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再仔细回看会发现，我们认为的“死”元组的lp状态是LP_NORMAL，而不是LP_DEAD。这个很重要，因为后面还会用到这个知识点。&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:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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&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;1&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1&lt;/span&gt;,&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为多了一个页，HOT不再适用，此时索引被更新了，索引页只有2个条目，而且都是活的dead=f，均指向各自page的第一个元组：(0,1) 和（1,1）。
页外的更新，索引页也会更新，每个索引条目指向各自的页。请注意，此时表里只有1条数据，索引有2个条目且都是活的，这也是为什么主键扫描会访问多个数据页。&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;DO&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;FOR&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; LOOP
&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; tab1 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;md5(i::text);
&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; LOOP; 
&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:#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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;1278&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&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;1277&lt;/span&gt;,&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; &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;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;(0,1)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(1,1)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;222&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;&lt;span style="color:#e6db74"&gt;&amp;#34;(222,1)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(223,1)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;444&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;&lt;span style="color:#e6db74"&gt;&amp;#34;(444,1)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(445,1)&amp;#34;&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;5&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;666&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;&lt;span style="color:#e6db74"&gt;&amp;#34;(666,1)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(667,1)&amp;#34;&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;6&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;888&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;&lt;span style="color:#e6db74"&gt;&amp;#34;(888,1)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(889,1)&amp;#34;&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;--第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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&amp;#39;&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;1278&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1278&lt;/span&gt;,&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; &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;1279&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1279&lt;/span&gt;,&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; &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;1280&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1280&lt;/span&gt;,&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; &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;1281&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1281&lt;/span&gt;,&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;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;152&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1429&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1429&lt;/span&gt;,&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; &lt;span style="color:#ae81ff"&gt;153&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1430&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;16&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&lt;/span&gt; &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;1430&lt;/span&gt;,&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;(&lt;span style="color:#ae81ff"&gt;153&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;--第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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; itemoffset, ctid, itemlen, nulls, vars, &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;, 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;idx_tab1_a&amp;#39;&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; 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; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &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;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:#ae81ff"&gt;8&lt;/span&gt; &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:#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;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:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &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:#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 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 style="color:#ae81ff"&gt;00&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;1277&lt;/span&gt;,&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;总共3个索引页，page1 是root节点，page 2和page 3是叶节点。他们的索引条目的dead状态都是“f”的&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;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;analyze&lt;/span&gt;,buffers) &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;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; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab1 (cost&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;39&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;41&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;14&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4012&lt;/span&gt;) (actual time&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;594&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;596&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:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: (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; Heap Blocks: exact&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1437&lt;/span&gt; dirtied&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1026&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 &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; idx_tab1_a (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;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;14&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;152&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;153&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;1431&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&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; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;087&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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;614&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;此时用主键查询，shared hit有1437，跟表的page有1430是差不多对得上的。
由于索引没有版本信息，而且索引条目的dead状态没有被更新，所以pg根据所有活的索引条目去数据页中找版本信息。这就是为什么走主键索引的SQL可以很慢。&lt;/p&gt;

&lt;h2 class="relative group"&gt;kill index item
 &lt;div id="kill-index-item" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#kill-index-item" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;由于索引没有存储可见性信息（即MVCC版本信息），索引所指向的元组的可见性信息决定了索引可见性本身。这也是为什么pg中的index-only-scan还是会访问数据页。当然有vm的话，vm会保留all-visible和all-frozen的数据页是哪些，此时的index-only-scan不会访问这些数据页，因为他们都可见了。
即便没有vacuum，pg内核仍有处理此类索引膨胀问题的方法——kill index item。这个特性有时候也叫Simple deletion or index deletion（&lt;code&gt;src/backend/access/nbtree/README&lt;/code&gt;的叫法），总之是&lt;strong&gt;将已经为LP_DEAD的元组所对应的索引条目标记为dead&lt;/strong&gt;，不改变原有的索引结构。
源码函数&lt;code&gt;_bt_killitems&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:#f92672"&gt;*&lt;/span&gt; _bt_killitems &lt;span style="color:#f92672"&gt;-&lt;/span&gt; set LP_DEAD state &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; items an indexscan caller has
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; told us were killed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;明确说明是索引扫描触发kill item操作（也就是说&lt;strong&gt;select也可能触发这个操作从而更新索引&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; tab2(a bigserial,b char(&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:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_tab2_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab2(a);
&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_tab2_b &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab2(b);
&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; tab2 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (autovacuum_enabled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&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;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; tab2 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;storage&lt;/span&gt; PLAIN; &lt;span style="color:#75715e"&gt;--关闭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;--插入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:#66d9ef"&gt;into&lt;/span&gt; tab2(b) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;00000&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;DO&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;FOR&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; LOOP
&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; tab2 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;i::text;
&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; LOOP; 
&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:#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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;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;tab2&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&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;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;2&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;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;115&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_COMBOCID,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;
&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;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;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;116&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_COMBOCID,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;
&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;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;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;117&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_COMBOCID,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;
&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;5&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;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;118&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_COMBOCID,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;
&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;6&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;119&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_COMBOCID,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;
&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;7&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;120&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_COMBOCID,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;
&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;8&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; LP_NORMAL &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;509&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;121&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_COMBOCID,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;
&lt;/span&gt;&lt;/span&gt;&lt;span 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;--a索引的页
&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; 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;idx_tab2_a&amp;#39;&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; 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;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &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:#ae81ff"&gt;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&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;2&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &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;5&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:#e6db74"&gt;&amp;#34;(44,5)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(44,6)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;47&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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:#e6db74"&gt;&amp;#34;(47,53)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(47,54)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;43&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:#e6db74"&gt;&amp;#34;(51,43)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(51,44)&amp;#34;&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;5&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;33&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:#e6db74"&gt;&amp;#34;(55,33)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(55,34)&amp;#34;&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;6&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;23&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:#e6db74"&gt;&amp;#34;(59,23)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(59,24)&amp;#34;&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;7&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:#ae81ff"&gt;8360&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; f &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:#ae81ff"&gt;63&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;13&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:#e6db74"&gt;&amp;#34;(63,13)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(63,14)&amp;#34;&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;--b索引的页
&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; 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;idx_tab2_b&amp;#39;&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; 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;57&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;112&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; &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;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;34&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;34&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;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:#ae81ff"&gt;41&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;41&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;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&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;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&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;7&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&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;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;57&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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; tab2;
&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; tab2 (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;204&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&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;3114&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;412&lt;/span&gt;) (actual time&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;077&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;079&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;173&lt;/span&gt; dirtied&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;173&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;042&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;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;090&lt;/span&gt; ms
&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; 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;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;tab2&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&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;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:#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_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&lt;/span&gt;&lt;/span&gt;&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;=&amp;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;idx_tab2_a&amp;#39;&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; 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;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &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:#ae81ff"&gt;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&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;2&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &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;5&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:#e6db74"&gt;&amp;#34;(44,5)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(44,6)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;47&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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:#e6db74"&gt;&amp;#34;(47,53)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(47,54)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;43&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:#e6db74"&gt;&amp;#34;(51,43)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(51,44)&amp;#34;&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;5&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;33&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:#e6db74"&gt;&amp;#34;(55,33)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(55,34)&amp;#34;&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;6&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; f &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;23&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:#e6db74"&gt;&amp;#34;(59,23)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(59,24)&amp;#34;&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;7&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:#ae81ff"&gt;8360&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; f &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:#ae81ff"&gt;63&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;13&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:#e6db74"&gt;&amp;#34;(63,13)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(63,14)&amp;#34;&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;7&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;=&amp;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;idx_tab2_b&amp;#39;&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; 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;57&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;112&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; &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;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;34&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;34&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;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:#ae81ff"&gt;41&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;41&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;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&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;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&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;7&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&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;数据元组，除了最后一个页其他都被标记为了LP_DEAD。
索引条目，什么都没动。
再用a索引查询一次表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; tab2 &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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_tab2_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab2 (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;68&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;56&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;16&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;412&lt;/span&gt;) (actual time&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;282&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;510&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;190&lt;/span&gt; dirtied&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;058&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;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;525&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;5&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;=&amp;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;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;tab2&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;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:#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_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_DEAD &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; 
&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; 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;idx_tab2_a&amp;#39;&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; 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;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &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:#ae81ff"&gt;66&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&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;2&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; t &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;5&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:#e6db74"&gt;&amp;#34;(44,5)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(44,6)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;47&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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:#e6db74"&gt;&amp;#34;(47,53)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(47,54)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;43&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:#e6db74"&gt;&amp;#34;(51,43)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(51,44)&amp;#34;&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;5&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;33&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:#e6db74"&gt;&amp;#34;(55,33)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(55,34)&amp;#34;&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;6&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:#ae81ff"&gt;8414&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&lt;/span&gt; &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; t &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;23&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:#e6db74"&gt;&amp;#34;(59,23)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(59,24)&amp;#34;&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;7&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:#ae81ff"&gt;8360&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; f &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; (&lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;13&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:#e6db74"&gt;&amp;#34;(63,13)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(63,14)&amp;#34;&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;7&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;=&amp;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;idx_tab2_b&amp;#39;&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; 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;57&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;112&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; &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;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;34&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;34&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;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:#ae81ff"&gt;41&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;41&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;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;53&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;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;54&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;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;55&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;7&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;56&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;56&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;索引a的死元组都被标记为了dead=t，而索引b的死元组还是dead=f，因为我们没有扫描过索引b。
此时再次通过索引a查询表&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; tab2 &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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_tab2_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab2 (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;68&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;56&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;16&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;412&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;020&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&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;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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;059&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;033&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;因为索引a上的死元组对应的索引条目都被标记为了dead=t，所以不需要再通过数据页上的版本信息来判断元组是不是“活”的。
为什么这里的shared hit=10呢，还是稍微有点多？因为kill index item只会标记死亡的索引条目，不会改变索引结构，索引页数没有减少，这10个shared hit就是10个索引页（包含meta页）。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;analyze&lt;/span&gt; tab2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ANALYZE&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; relname,relpages,reltuples &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;idx_tab2_a&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; relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_tab2_a &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;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;Bottom-Up deletion
 &lt;div id="bottom-up-deletion" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#bottom-up-deletion" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在pg14中，index deletion功能的触发条件有增强。前面已经提到，触发index deletion的条件是扫描索引，pg14中还可以在即将发生索引分裂时，触发index deletion，以找到空闲的索引空间，减少索引分裂的概率。
当然这个特性减少了索引分离，也同样减少了索引膨胀，从而缓解索引膨胀带来的问题。&lt;/p&gt;
&lt;p&gt;具体的测试可参考：&lt;a href="https://www.cybertec-postgresql.com/en/index-bloat-reduced-in-postgresql-v14/?spm=a2c6h.12873639.article-detail.8.2f153438mIV8JK" target="_blank" rel="noreferrer"&gt;INDEX BLOAT REDUCED IN POSTGRESQL V14&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;index deduplication
 &lt;div id="index-deduplication" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#index-deduplication" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;pg13引入了index deduplication的特性，它将GIN索引的posting list思想，引入到btree索引中，以减少btree重复索引占用的空间并缓解索引分裂问题。
原本btree索引条目只指向一个ctid（就像我们前面测试看到的那样），有了deduplicate index item，一个索引条目可以有一个posting list，一个posting list可以存放多个ctid。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The representation of posting lists is almost identical to the posting lists used by GIN&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;like GIN posting tree(list)（*btree的posting list不一定是这个结构，待研究）：



&lt;img src="https://lastdba.com/img/csdn/8b0c1a3b1562.png" alt="在这里插入图片描述" /&gt;
（https://postgrespro.com/blog/pgsql/4261647）&lt;/p&gt;
&lt;p&gt;对index deduplication的测试：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; tab3(same char(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;),diff char(&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:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_tab3_same &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab3(same);
&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_tab3_diff &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab3(diff);
&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; tab3 &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;::text,i::text &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;99999&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; i;&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:#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;idx_tab3_same&amp;#39;&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; 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;104&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4097&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;120&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; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;104&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10&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;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8398&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&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;69&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;19&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:#e6db74"&gt;&amp;#34;(69,19)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(69,20)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8398&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&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;75&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;21&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:#e6db74"&gt;&amp;#34;(75,21)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(75,22)&amp;#34;&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:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8398&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&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;81&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;23&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:#e6db74"&gt;&amp;#34;(81,23)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(81,24)&amp;#34;&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;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8398&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&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;87&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;25&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:#e6db74"&gt;&amp;#34;(87,25)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(87,26)&amp;#34;&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;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8398&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1352&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;93&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;27&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:#e6db74"&gt;&amp;#34;(93,27)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(93,28)&amp;#34;&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;7&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;112&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;8344&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; 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;99&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;29&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:#e6db74"&gt;&amp;#34;(99,29)&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;(99,30)&amp;#34;&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;7&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;=&amp;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;idx_tab3_diff&amp;#39;&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; 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;5&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;112&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; &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;2&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:#ae81ff"&gt;23&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;23&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;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:#ae81ff"&gt;24&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;24&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; &lt;span style="color:#ae81ff"&gt;62&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:#ae81ff"&gt;15&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;15&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;63&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:#ae81ff"&gt;16&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;112&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;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;16&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;63&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;bt_page_items函数里面的tids列其实就是posting list。上面的same字段插入的是同一个相同的数据，索引产生了deduplication；diff字段没有相同的数据，没有产生deduplication。
他们各自所占用的空间差异是非常大的:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; relname,relpages,reltuples &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:#66d9ef"&gt;like&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;idx_tab3%&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; relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;---------------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;idx_tab3_diff &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1484&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;90000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;idx_tab3_same &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;81&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;90000&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;唯一索引会产生deduplication吗？
 &lt;div id="唯一索引会产生deduplication吗" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%94%af%e4%b8%80%e7%b4%a2%e5%bc%95%e4%bc%9a%e4%ba%a7%e7%94%9fdeduplication%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;唯一索引没有重复数据，看上去是不会，实际上是会的。因为即便是唯一索引，在HOT满足不了更新的时候，就会产生多个索引条目。这个测试我们从本文的第一个测试用例就可以看出来。update反复更新一条记录，也会产生deduplication，它产生在delete index item之前。
另外，delete index item在删除posting list索引时，需要确保posting list下的&lt;strong&gt;所有&lt;/strong&gt;ctids所对应的元组都是DEAD的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;关闭deduplication
 &lt;div id="关闭deduplication" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%b3%e9%97%addeduplication" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;index deduplication是pg13引入的。该功能默认开启，可以在索引级别关闭该功能。修改索引的deduplicate_items不会直接改动现有的索引结构，只会影响新插入的数据。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;index&lt;/span&gt; idx_tab3_same &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (deduplicate_items&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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_tab3_same1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab3(same) &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; (deduplicate_items&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 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="#vacuum%e5%81%9a%e4%ba%86%e4%bb%80%e4%b9%88" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;vacuum做的事情挺多的，这里只关注表、索引膨胀和空间回收，回卷等事情就不看了。&lt;/p&gt;
&lt;p&gt;拿刚才反复更新一条数据的tab2表来测试，已经触发过simple deletion，表和索引条目几乎都是DEAD。
直接执行vacuum&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;vacuum&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;verbose&lt;/span&gt; tab2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: vacuuming &lt;span style="color:#e6db74"&gt;&amp;#34;public.tab2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: scanned &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_tab2_a&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; remove &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: scanned &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_tab2_b&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; remove &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#e6db74"&gt;&amp;#34;tab2&amp;#34;&lt;/span&gt;: removed &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;173&lt;/span&gt; pages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_tab2_a&amp;#34;&lt;/span&gt; now &lt;span style="color:#66d9ef"&gt;contains&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; pages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions were removed.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; pages have been deleted, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; currently reusable.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_tab2_b&amp;#34;&lt;/span&gt; now &lt;span style="color:#66d9ef"&gt;contains&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;276&lt;/span&gt; pages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions were removed.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;269&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; pages have been deleted, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; currently reusable.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;INFO: &lt;span style="color:#e6db74"&gt;&amp;#34;tab2&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;found&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; removable, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; nonremovable &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;173&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;173&lt;/span&gt; pages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DETAIL: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; dead &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; versions cannot be removed yet, oldest xmin: &lt;span style="color:#ae81ff"&gt;526&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There were &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; unused item identifiers.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Skipped &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; pages due &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; buffer pins, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; frozen pages.
&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; pages &lt;span style="color:#66d9ef"&gt;are&lt;/span&gt; entirely empty.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CPU: &lt;span style="color:#66d9ef"&gt;user&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;system&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s, elapsed: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; s.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;VACUUM&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;idx_tab2_a索引在10个page中remove了 10000个行版本，7个index pages被delete
tab2表在173个page中remove了10000个行版本。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;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;tab2&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;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:#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_UNUSED &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_UNUSED &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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#ae81ff"&gt;45&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_UNUSED &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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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; 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;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;tab2&amp;#39;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;172&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;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:#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_UNUSED &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; 
&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:#f92672"&gt;|&lt;/span&gt; LP_UNUSED &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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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:#ae81ff"&gt;23&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_UNUSED &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; 
&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;24&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LP_UNUSED &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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25&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;509&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;9999&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&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&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; 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;idx_tab2_a&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;NOTICE: page &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; deleted
&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;4294967295&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;8&lt;/span&gt; &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&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;lzldb&lt;span style="color:#f92672"&gt;=&amp;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;idx_tab2_a&amp;#39;&lt;/span&gt;,&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;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;172&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;25&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; f &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:#ae81ff"&gt;172&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;25&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;表的死元组所在的lp全部被标记为UNUSED，数据被清理，只剩下一条活元组在表中为NORMAL状态，表的pages还是那么多。
索引的死元组（dead=t）的全部被清理，索引活元组在索引页内被移位了（最后一页的索引元组原本的itemoffset&amp;lt;&amp;gt;1），所有被清空的索引页被标记为deleted，这些deleted的索引页其实还在，为半死状态——half dead。
nbtree README中对Deleting entire pages during VACUUM的解释（原文比较长，摘了比较重要的出来）：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;We consider deleting an entire page from the btree only when it&amp;rsquo;s become
completely empty of items.
Page deletion always begins from an empty leaf page. An
internal page can only be deleted as part of deleting an entire subtree.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;只有当索引页完全为空的时候才会考虑delete entire page。deleting总是从页节点开始，non-leaf节点只有在删除整个子树时才会被删除。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Deleting a leaf page is a two-stage process.&lt;br&gt;
In the first stage, the page
is unlinked from its parent, and marked as half-dead.
In the second-stage, the half-dead leaf page is unlinked from its siblings.
We first lock the left sibling (if any) of the target, the target page
itself, and its right sibling (there must be one) in that order. Then we
update the side-links in the siblings, and mark the target page deleted.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;删除页节点有2个阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从父节点unlink，此时的页节点为half-dead状态&lt;/li&gt;
&lt;li&gt;从左右兄弟节点unlink，此时的叶节点为deleted状态&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;A deleted page cannot be recycled immediately, since there may be other
processes waiting to reference it (ie, search processes that just left the
parent, or scans moving right or left from one of the siblings). These
processes must be able to observe a deleted page for some time after the
deletion operation, in order to be able to at least recover from it (they
recover by moving right, as with concurrent page splits). Searchers never
have to worry about concurrent page recycling.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;因为其他进程可能还在使用deleted page，vacuum不能立即回收这些索引页。&lt;/p&gt;
&lt;p&gt;这段描述跟我们看到的现象是一致的
虽然vacuum后，索引的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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; relname &lt;span style="color:#f92672"&gt;|&lt;/span&gt; relpages &lt;span style="color:#f92672"&gt;|&lt;/span&gt; reltuples 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;------------+----------+-----------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx_tab2_a &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;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tab2 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;173&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;但是通过索引扫描已经不需要访问deleted page了：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers) &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; tab2 &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;; 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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_tab2_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab2 (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;12&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&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;109&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;011&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;012&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;056&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;025&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;vacuum之前shared hit=10，vacuum后索引page数没有变，还是有10个，其中有8个pages被deleted 但是没有直接recycle，所以shared hit=2。为什么是2也很容易理解，就是“meta page” + “只有一个存活的leaf page”。&lt;/p&gt;

&lt;h2 class="relative group"&gt;Placing deleted pages in the FSM
 &lt;div id="placing-deleted-pages-in-the-fsm" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#placing-deleted-pages-in-the-fsm" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;Recycling a page is decoupled from page deletion. A deleted page can only
be put in the FSM to be recycled once there is no possible scan or search
that has a reference to it; until then, it must stay in place with its
sibling links undisturbed, as a tombstone that allows concurrent searches
to detect and then recover from concurrent deletions (which are rather
like concurrent page splits to searchers)&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;什么是Placing deleted pages in the FSM&lt;/strong&gt;？在索引页被deleted后，并没有被直接recycle，索引在分裂或新增页时，很难找到被deleted pages重复利用。Placing deleted pages in the FSM便是把这些可回收的页放在索引对应的FSM文件中，方便找到可直接利用的空闲页。
我们前面提到，首次vacuum的时候，哪些deleted pages虽然被unlink了，但是它还是在那里占用着空间，在pg14以前&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;We implement the technique by waiting until all active snapshots and
registered snapshots as of the page deletion are gone&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;删除的条件之一：所有活动快照和delete pages所涉及的快照必须都必须都结束。所以长事务肯定影响placing。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Placing an already-deleted page in the FSM to be recycled when needed
doesn&amp;rsquo;t actually change the state of the page. The page will be changed
whenever it is subsequently taken from the FSM for reuse. The deleted
page&amp;rsquo;s contents will be overwritten by the split operation (it will become
the new right sibling page).&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;此外，把 already-deleted page放到FSM文件中不会改变页的状态，这只是为了快速找到可用空闲页。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Prior to PostgreSQL 14, VACUUM would only place &lt;em&gt;old&lt;/em&gt; deleted pages that
it encounters during its linear scan (pages deleted by a previous VACUUM
operation) in the FSM. Newly deleted pages were never placed in the FSM,
because that was assumed to &lt;em&gt;always&lt;/em&gt; be unsafe.
PostgreSQL 14 added the ability for VACUUM to consider if it&amp;rsquo;s possible to
recycle newly deleted pages at the end of the full index scan where the
page deletion took place&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;在PG14以前，第一次vacuum产生的deleted pages不会被放到FSM，只有“旧”的deleted pages才会被放到FSM文件中。
在PG14之后，第一次vacuum也会考虑将deleted pages放到FSM中。&lt;/p&gt;
&lt;p&gt;测试（我的版本是pg13）：
上面的tab2测试刚跑了一次vacuum，虽然已经产生了deleted pages，但是索引没有对应的FSM文件：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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_relation_filepath(&lt;span style="color:#e6db74"&gt;&amp;#39;idx_tab2_a&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;16384&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16437&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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;lzlhost &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll base&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;&lt;span style="color:#ae81ff"&gt;16437&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;rw&lt;span style="color:#75715e"&gt;------- 1 postgres postgres 81920 Apr 5 11:04 base/16384/16437&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：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;vacuum&lt;/span&gt; tab2;
&lt;/span&gt;&lt;/span&gt;&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;lzlhost &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; ll base&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;&lt;span style="color:#ae81ff"&gt;16437&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;rw&lt;span style="color:#75715e"&gt;------- 1 postgres postgres 81920 Apr 5 11:04 base/16384/16437
&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 postgres postgres 24576 Apr 5 15:52 base/16384/16437_fsm&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;索引立即产生了fsm文件。&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%81%e7%a8%8b%e5%9b%be%e7%b4%a2%e5%bc%95%e8%86%a8%e8%83%80%e5%92%8c%e6%b8%85%e7%90%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;请注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下图不包含表的fsm、vm信息&lt;/li&gt;
&lt;li&gt;下图不包含deduplication信息&lt;/li&gt;
&lt;li&gt;版本为pg13



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

&lt;h2 class="relative group"&gt;fillfactor
 &lt;div id="fillfactor" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fillfactor" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;以上讲了各种pg内核支持的方式以减少索引膨胀，出这些我们基本不需要参与的方式，还可以调整表和索引的fillfactor来控制膨胀问题。&lt;/p&gt;
&lt;p&gt;fillfactor相当于表或索引的水位线，在&lt;strong&gt;INSERT&lt;/strong&gt;数据时，插入到page的fillfactor线就到下一页去插入。fillfactor本身是为了给update留一定的空间，防止update频繁的去寻找新的page。&lt;/p&gt;
&lt;p&gt;虽然表和索引都有fillfactor，他们的目的是一样的（为了update），但是具体细节有很大区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表：如果表的某个page上还有留有空间，那么update可以在这个page中进行，不需要申请新的page或者到其他有空闲空间的page上去。不仅如此，因为PG 独有的HOT特性，页内更新不会更新索引，当然也就会减缓索引膨胀&lt;/li&gt;
&lt;li&gt;索引：不同的数据行或者相同数据行的页外更新，会新生成索引条目。fillfactor给索引页留下余量，会极大的减缓索引分离问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，fillfactor的设置跟业务模型是息息相关的，如果数据类似日志那样是递增且完全没有更新的，那么表和索引的fillfactor设置成100无可厚非。但是大部分业务表总是有更新的，表和索引fillfactor就不应该设置成100，如果是频繁的update，那么fillfactor应该设置得更低。
然而，pg默认的fillfactor如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表默认 fillfactor=100&lt;/li&gt;
&lt;li&gt;索引默认 fillfactor=90&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表fillfactor=100完全用不了HOT！只要更新立即寻找新数据页，并在索引的10%里去新增一个索引元组。最后导致update频繁的业务总是在更新索引，此时90的索引也撑不住了，最终导致update频繁造成索引分裂···&lt;/p&gt;
&lt;p&gt;以下是对fillfactor的测试，两张表仅fillfactor不一样，更新相同量的数据，看看最终share hit的差异：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; tab4(a bigserial,b char(&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:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; idx_tab4_a &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab4(a);
&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_tab4_a &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (deduplicate_items&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--关闭索引的deduplication
&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; tab4 &lt;span style="color:#66d9ef"&gt;alter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; b &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;storage&lt;/span&gt; PLAIN; &lt;span style="color:#75715e"&gt;--关闭toast
&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; tab4 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (autovacuum_enabled &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;off&lt;/span&gt;); &lt;span style="color:#75715e"&gt;--关闭autovacuum&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;--tab5跟表tab4定义一样，除了表和索引的fillfactor更新
&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; tab5 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (fillfactor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;70&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_tab5_a &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; (fillfactor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;80&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; tab4(b) &lt;span style="color:#66d9ef"&gt;values&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;lllllllllll&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 style="color:#66d9ef"&gt;DO&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;FOR&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; LOOP
&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; tab4 &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;md5(i::text) &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;END&lt;/span&gt; LOOP; 
&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:#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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--默认fillfactor的主键查询
&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;analyze&lt;/span&gt;,buffers) &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; tab4 &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; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab4 (cost&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;28&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;53&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;16&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;412&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;894&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;895&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:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: (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; Heap Blocks: exact&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;174&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 &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; idx_tab4_a (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;4&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;16&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;023&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;023&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;173&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;057&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;913&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;9&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;--fillfactor调低后的主键查询
&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;analyze&lt;/span&gt;,buffers) &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; tab5 &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; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; tab5 (cost&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;39&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;56&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;41&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;14&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4012&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;367&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;369&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:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: (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; Heap Blocks: exact&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1434&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 &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; idx_tab5_a (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;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;14&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;195&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;195&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;1429&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;059&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;3&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;390&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;fillfactor调低后，shared hit的降低是非常明显的，Execution Time也有数倍提升。实际上数据页和索引页都有减少。
所以，在总是update的业务表中，设置调低表和索引的fillfactor可以缓解表膨胀问题。&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;p&gt;虽然索引膨胀总是伴随着表膨胀，但是他们的原理不太一样。HOT不会更新索引元组，页外更新会新增索引元组。
将表和索引的fillfactor参数调低，可以减缓update频繁的业务表的膨胀问题，当然最终也减缓了主键查询等SQL变慢问题。
另外还有一些内核自带的增效索引空间的功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;扫描索引时顺便清理死亡索引元组（index tuple deletion）&lt;/li&gt;
&lt;li&gt;索引分裂时清理死亡索引元组（Bottom-Up index tuple deletion）&lt;/li&gt;
&lt;li&gt;vacuum标记全是死索引元组的页（Deleting entire pages during VACUUM）&lt;/li&gt;
&lt;li&gt;快速定位以在索引分离时更快的找到回收的索引页（Placing deleted pages in the FSM）&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;p&gt;src/backend/access/nbtree/README
&lt;a href="https://mp.weixin.qq.com/s/GBN7dFQU72BfzvLSzlLmYA" target="_blank" rel="noreferrer"&gt;https://mp.weixin.qq.com/s/GBN7dFQU72BfzvLSzlLmYA&lt;/a&gt;
&lt;a href="https://blog.csdn.net/qq_40687433/article/details/130782857?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171221125016800182737655%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=171221125016800182737655&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=lp_flags&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;pg事务：事务相关元组结构&lt;/a&gt;
&lt;a href="https://www.cybertec-postgresql.com/en/killed-index-tuples/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/killed-index-tuples/&lt;/a&gt;
&lt;a href="https://www.cybertec-postgresql.com/en/index-bloat-reduced-in-postgresql-v14/?spm=a2c6h.12873639.article-detail.8.2f153438mIV8JK" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/index-bloat-reduced-in-postgresql-v14/?spm=a2c6h.12873639.article-detail.8.2f153438mIV8JK&lt;/a&gt;
&lt;a href="https://www.cybertec-postgresql.com/en/b-tree-index-improvements-in-postgresql-v12/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/b-tree-index-improvements-in-postgresql-v12/&lt;/a&gt;
&lt;a href="https://www.cybertec-postgresql.com/en/b-tree-index-deduplication/" target="_blank" rel="noreferrer"&gt;https://www.cybertec-postgresql.com/en/b-tree-index-deduplication/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《2001太空漫游》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B02001%E5%A4%AA%E7%A9%BA%E6%BC%AB%E6%B8%B8/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B02001%E5%A4%AA%E7%A9%BA%E6%BC%AB%E6%B8%B8/</guid><description>&lt;p&gt;​
        ​​&lt;/p&gt;
&lt;p&gt;        阿瑟·克拉克神作，任何一个科幻迷都绕不开的一部作品。很早就听说过其大名，因为之前看过电影版的，总感觉少了点新鲜感，这本书就一直在书架上没有拿出来看。但是看过这本书后，我可以很负责任的说，全书都充满新鲜感，是那种多巴胺驱动看书的书，根本停不下来。&lt;/p&gt;</description><content:encoded>&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="#%e7%a5%9e%e7%ba%a7%e9%a2%84%e6%b5%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        本书出版在上世纪60年代，距今（2023年）已过去60多年了。何为科幻？科幻是在当前的科学基础上对未来做出比较合理的幻想。而身处60年代的作者，幻想了2000年的人类对宇宙的探索，而身处现在的我们，刚好可以对其描述的“未来世界”进行验证。
        这些作者的神预言当然不是丝毫不差的，比如载人宇宙航行的预测明显有点过于乐观，阿波罗计划结束后我们再也没有脱离地球束缚的实践，哪怕是再次登上月球···
而小说中的2000年，人类已经有豪华的月球基地，并派遣航天员乘坐宇宙飞船前往木星。
不过这真不怪作者，本书于1968年出版，次年人类就登陆月球了。想想再给人类几十年，登陆个木星应该问题不大吧~&lt;/p&gt;
&lt;p&gt; 小说有很多神预测，列举几个印象深刻的：
人口：阿瑟·克拉克极其准确的预言了2000年人口暴增到60亿（60年代人口是30亿）。甚至预言某些国家因为人口过多开始实行计划生育，一个家庭最多生两胎（明显保守了对吧··震旦天朝早开始实行计划生育，而且只能生一胎，直到年轻人不再想生）
疫情防控：2000年地球社会蔓延疫情，到处设置隔离区···（无fuc.k说）
人工智能：1946冯·诺依曼发明了计算机，计算机这个概念才刚刚兴起，阿瑟·克拉克已经在强调人工智能这个概念，预言人工智能对庞大繁杂系统的控制，更甚的是，他已经想到了人工智能可能叛变人类···ChatGPT今年才被认可，细思极恐~
平板电脑：家用计算机在80年代才出现，小说中人们已经在用平板电脑控制系统输入，查看新闻···由于小说过于硬核，阿瑟·克拉克甚至描述了平板电脑上新闻的主页和其他分类页面的切换，并通过数据分析投送用户想要的内容···
三中心镜像：作为dba的我，对这个词实在是太过于敏感。作者描述了数据中心的镜像备份，并把数据分3份完全一致的镜像放在地球不同的地方，以作容灾···两地三中心、三地五中心等等概念我也不太确定是什么时候提出的（但我想肯定不久），但是看到小说对数据镜像、异地容灾的概念描述的如此详尽，确实触动到我的dba基因了。
        拜读这个神作，我的心态是震惊，再震惊，不停地震惊~60年代的阿瑟·克拉克是怎么构思未来世界的？难以想象。怪不得有人说“阿瑟·克拉克穿越到现在，然后回到60年代写了这部作品”。&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%b9%bb%e6%83%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;         如果仅仅是对科学的预测，其实不能称为科幻。科幻不能只是冷冰冰的科学推测，还需要加入一些人文提炼，需要一点脱离科学的幻想，比如老刘作品对于人性描述等等。这部分脱离科学的幻想恰恰其实决定了科幻作品的最终高度。
        而《2001太空漫游》的终极幻想是TMA-1石板和星孩。TMA-1石板是外星生命对人类进化的启发物，同时也代表了人类科学与外星科学的差距。小说全篇都在围绕这个石板讲诉故事，这个石板其实就是整部科幻小说的核心。其实石板只出现在2个时间点：猿人和人类开始太空探索时。猿人第一次接触了石板后，他们的身体结构发生了细微的变化，他们的手更灵活，大脑开始思考。后续作者用了几个篇章描述了猿人的变化：
        1.这群猿人掌握了工具，在与豹子的争斗中，历史第一次占据了上风，标志着他们第一次站在了食物链的顶端，不再是被捕食者。
        2.这群猿人在与其他种群的猿人争斗过程中完胜，标志着他们从猿人蜕变，成为人类。
        随后，小说跳过几百万年的人类历史，直接把镜头切换到太空旅行年代。这个手法太精彩了~
        第二次，唯一一个人类历经千辛万苦接触了土星上的石板，主角通过外星生命提前布置好的虫洞，经历太空穿越旅行，见证许多神奇的宇宙奇观，最后坠入一个房间，星孩诞生！
        外星生命指引猿人成为人类，再指引人类成为星孩。星孩就是幻想，基于猿人成为人类的类比，以TMA-1石板为标志。恰如其分的加入幻想元素，又那么的顺理成章，回味无穷，不愧是科幻界的代表作。&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%80%81%e5%88%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        老刘的作品在大学期间看了不少，《三体》、《流浪地球》、《球状闪电》、《地球大炮》··· 我很喜欢《三体》，但是对《三体一》里面过多的派系争端实在没兴趣，甚至觉得有点“扯把子”。不过通过三体游戏理解三体社会这个设定，非常精彩。《三体二》明显就好很多，可谓三部曲中最精彩的一本。当时看我完这些作品就觉着《流浪地球》可能会拍电影，其他几个都不太好拍···
        老刘的科幻作品有很强的剧情悬念和很多的人文冲突，更多的是在宇宙背景下的人的行为。而阿瑟·克拉克的作品很少聚焦于人际关系，他更喜欢描绘未来社会的样貌，以及对星空、星球、太空旅行的光怪陆离。
        老刘作品有很多地方能看出来有《太空漫游》的影子。阿瑟·克拉克再描述TMA-1的时候，使用了“光滑”这个词，明显《三体》中的“水滴”参考了这个设定。他们都是人类无法理解的外星生物的科技产品，用途确实千差万别~
        话说老刘已经十多年没有出作品了，在搞啥呢···
      &lt;/p&gt;

&lt;h2 class="relative group"&gt;电影版《2001太空漫游》
 &lt;div id="电影版2001太空漫游" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%b5%e5%bd%b1%e7%89%882001%e5%a4%aa%e7%a9%ba%e6%bc%ab%e6%b8%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        1968年上映的电影，库布里克的又一神作，科幻之神+电影之神。
        经典的BGM响起&lt;del&gt;当猿人把充当工具的大骨扔上天再掉下来的时候，镜头切换到几百万后···极其妙手的镜头语言，令人心潮澎湃&lt;/del&gt;
        之前看这部电影的时候，其实有很多地方没看明白，看完小说一切都顺理成章。电影中还添加了很多经典的镜头，比如：
        1.对2000年地球外围太空的幻想。经过30多年的发展，人类已经发射了很多太空舱到天上，到处都是各式各样的太空飞船，这个片段在2000年前被经常引用
        2.哈尔9000通过读唇语知道飞行员要把自己干掉。我以为这一幕是小说里本身就有的，但小说里对干掉AI的情节要曲折很多。不过都很精彩。（《流浪地球》电影版MOSS致敬哈尔9000挺多的）
      &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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        《太空漫游》完美描述了硬核科幻应有的样子：对未来的神级预测，以及画龙点睛式幻想。这本书读的太晚了，后面一定要多看几本后续的系列！&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《When Breath Becomes Air》和《超越自卑》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0when-breath-becomes-air%E5%92%8C%E8%B6%85%E8%B6%8A%E8%87%AA%E5%8D%91/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0when-breath-becomes-air%E5%92%8C%E8%B6%85%E8%B6%8A%E8%87%AA%E5%8D%91/</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%b8%ba%e5%95%a5%e8%a6%81%e4%b8%a4%e6%9c%ac%e4%b9%a6%e4%b8%80%e8%b5%b7%e5%86%99%e8%af%bb%e5%90%8e%e6%84%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;读完这两本书本来应该分开来写点东西的，不过我认为这两本书应该写不了太多内容。虽然我也看了几本英文原著（也写了点东西），但是我明显低估了《when breath becomes air》的难度，里面有大量不认识的单词，很多是没有见过的医学名词，算是看了个半懂强行给看完了。《超越自卑》呢，感觉没有说的那么神奇吧，毕竟年代过于久远了，我没有在其中获取很多营养（少量还是有点）。为了不让内容过少而看起来尴尬，就凑在一起写吧。&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%b8%ba%e5%95%a5%e8%a6%81%e4%b8%a4%e6%9c%ac%e4%b9%a6%e4%b8%80%e8%b5%b7%e5%86%99%e8%af%bb%e5%90%8e%e6%84%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;读完这两本书本来应该分开来写点东西的，不过我认为这两本书应该写不了太多内容。虽然我也看了几本英文原著（也写了点东西），但是我明显低估了《when breath becomes air》的难度，里面有大量不认识的单词，很多是没有见过的医学名词，算是看了个半懂强行给看完了。《超越自卑》呢，感觉没有说的那么神奇吧，毕竟年代过于久远了，我没有在其中获取很多营养（少量还是有点）。为了不让内容过少而看起来尴尬，就凑在一起写吧。&lt;/p&gt;
&lt;p&gt;


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

&lt;h2 class="relative group"&gt;《when breath becomes air》
 &lt;div id="when-breath-becomes-air" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#when-breath-becomes-air" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;作者是一个外科医生，在医学上有非常高的成就，就在他到达人生巅峰时，得知自己患癌症晚期。从得知癌症不到2年时间便离开人世。这是本书便是他在这2年内著成。本书从“第一视角”描述一个人会怎么看待癌症这类的不幸、在弥留之际对人生、生命的思考。&lt;/p&gt;
&lt;p&gt;当他在得知自己癌症晚期时，作为一个顶尖外科医生他知道这意味着什么，他知道自己活不久了。刚开始他甚至愤怒，为什么这么低概率的事情发生在我身上，why me？这种事情发生在任何人身上都是难以接受的。但是只有真正患病的人才会与病痛为伴，静静地走向那即将发生但没有具体时间线的死亡。&lt;/p&gt;
&lt;p&gt;在患病后，他和他妻子决定立即生个小孩，赶在化疗之前。作者也赶在去世之前陪伴了几个月宝宝。他也想陪伴宝贝女儿成长，想知道宝贝女儿长大后会是什么样子，不过他很确信自己不可能知道了。这似乎太残酷了。&lt;/p&gt;
&lt;p&gt;在看到快结束的时候（大概还有2、30页的内容），作者的文笔戛然而止。随后是她妻子为他写的篇章，开篇便是PAUL离我们而去了···即使知道结局会是怎样，我甚至都无法接受，死亡来的那么突然，甚至连著作都没有完全完成···但是反过来思考，对于这本书的立意，这反倒是一种完成···&lt;/p&gt;
&lt;p&gt;我们应该怎样看待死亡呢，假设在40岁不到就撒手人寰，我会做什么？我肯定会不甘，我有太多事情没有完成。作者最后看透了生命的意义，他认为最重要的是经历人生和在当下一刻。
我好像不太一样啊，我活在未来，never now！如果我现在go die了，那我就要伴随着愤怒和怨恨离世。&lt;/p&gt;
&lt;p&gt;（他的经历很容易让人联想到日剧《白色巨塔》，超棒的日剧！财前教授在人生巅峰的时候患癌，最后为了医学捐献自己的躯体用作癌症病理学研究···）&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/0b8ac609261a.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="#%e8%b6%85%e8%b6%8a%e8%87%aa%e5%8d%91" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;个体心理学创始人阿德勒所处心理学名著。很久前看《老高和小茉》讲过一期阿德勒和个体心理学，也是说的神乎其神的，忍不住看了，顺便看看能不能分析分析自己。&lt;/p&gt;
&lt;p&gt;个体心理学最重要的观点是：我们怎么看待心理创伤经历才是心理问题的本质，而不是经历本身使人们产生心理问题。但是这不是在否认“过去”对人们行为的影响。&lt;/p&gt;
&lt;p&gt;然而个人看下来，该书有点无聊···“有点偏文科”，小篇章之间内容的本质差距其实不大，只不过是换了个话题聊个体心理，我确实无法从中汲取大量的营养，可能是书成著于100年前，也可能我不是这块料。&lt;/p&gt;
&lt;p&gt;阿德勒还提出一个观点：一个集体（或者夫妻）应该为这个集体思考和谋利，才不会出现集体分离的问题。如果有一个人有为自己谋利的想法，那么这个集体一定是不稳定的。不能再赞同。其实也可以写点自我分析出来，但是我并不想暴露自己，这也是为啥我觉得这个读后感不会很丰满的原因。&lt;/p&gt;
&lt;p&gt;在看《自卑》这本书前还看了一点点《被讨厌的勇气》《人性的弱点》。因为看到他俩评分都比《超越自卑》这个祖师爷高，就看看写的到底是什么，结果都很不喜欢。《勇气》就是两个人对话，典中典智者和学者的对话形式，从这些对话中了解书要说什么···看了一点就看不下去了，畅销书style。《弱点》这本书倒还能看看，直接把人生建议直白的描述出来，我大概看了十条，还是有点价值的，但是也看不下去了，畅销书style too。&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;看了几本英语原著显然我有点飘了，看来还是得量力而为，先观察观察难度再上。
之前很想看心理学，看完发现我不是这块料。
ok，无论如何都要写出来这个读后感，记录人生，像PAUL那样。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《黑猩猩的政治》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E9%BB%91%E7%8C%A9%E7%8C%A9%E7%9A%84%E6%94%BF%E6%B2%BB/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E9%BB%91%E7%8C%A9%E7%8C%A9%E7%9A%84%E6%94%BF%E6%B2%BB/</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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;弗朗斯·德瓦尔（Frans de Waal)的代表作《黑猩猩政治》成书于1982年，是它的首部书籍作品，也是美国国会新任议员的被推荐读物。之前看的他另一部作品的《万智有灵》是2016年的作品，时间跨度居然这么大。《万智有灵》介绍了许多动物行为包括人类的许多近亲，而《黑猩猩政治》只描述了一种离我们最近的近亲——黑猩猩。它观察了某动物园中的黑猩猩群体，并对黑猩猩社会的政治权利结构、演化、行为等等进行观察和剖析。&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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;弗朗斯·德瓦尔（Frans de Waal)的代表作《黑猩猩政治》成书于1982年，是它的首部书籍作品，也是美国国会新任议员的被推荐读物。之前看的他另一部作品的《万智有灵》是2016年的作品，时间跨度居然这么大。《万智有灵》介绍了许多动物行为包括人类的许多近亲，而《黑猩猩政治》只描述了一种离我们最近的近亲——黑猩猩。它观察了某动物园中的黑猩猩群体，并对黑猩猩社会的政治权利结构、演化、行为等等进行观察和剖析。&lt;/p&gt;
&lt;p&gt;如果你在动物园中看到黑猩猩光天化日毫无禁忌地交配，或者相互嘶吼攻击，看上去毫无道德约束，完全没有文明的体现，那么《万智有灵》的英文标题可以很好的怼回去：“&lt;em&gt;Are We Smart Enough to Know How Smart Animals Are?&lt;/em&gt;”



&lt;img src="https://lastdba.com/img/csdn/da1153babfbb.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="#%e6%9d%83%e5%8a%9b%e4%b8%8e%e8%81%94%e7%9b%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;p&gt;在耶罗恩倒台前，尼基是鲁伊特的盟友，之后，尼基是耶罗恩的盟友。老练的耶罗恩为什么要在失权后支持尼基？&lt;/p&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;/ul&gt;
&lt;p&gt;耶罗恩-尼基的联盟虽然紧密，但是耶罗恩却非常狡猾。虽然耶罗恩与鲁伊特的关系很不好，但耶罗恩还是会主动接触鲁伊特，此时尼基肯定会去干扰，没有例外。为什么耶罗恩要去接触鲁伊特？耶罗恩接触鲁伊特就是为了演戏给尼基看。对于尼基来讲，耶罗恩的行为时刻在提醒他，他的地位稳定与否完全取决于耶罗恩的选择。年轻的尼基没有群众的强烈支持，老练狡猾的耶罗恩将尼基至于自己的掌心，执政基础并不在尼基的脚下。&lt;/p&gt;
&lt;p&gt;一个黑猩猩给另一个黑猩猩护理皮毛，这不仅仅是一个简单的生物行为，而是两只黑猩猩社会关系的映射，代表他们关系足够好或者有求于人。三角关系中的一种典型情形。尼基（中）在给他的盟友耶罗恩（左）护理毛皮，而这时，鲁伊特（右）则在一个相距不远的地方独自坐着。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/4428a0cfefba.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="#%e6%9d%83%e5%88%a9%e4%b8%ad%e7%9a%84%e7%94%b7%e6%80%a7%e4%b8%8e%e5%a5%b3%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;虽然雄性普遍比雌性更强大，但雄性黑猩猩在攻击雌性的时候，并不会使用全力，雄性只有在面对另一只雄性的时候才会撕咬对方。&lt;/p&gt;
&lt;p&gt;社会性哺乳动物群体通常由许多雌性和合少数雄性组成。女性同样在权力斗争中发挥着重要角色。&lt;/p&gt;
&lt;p&gt;雌黑猩猩倾向于避免竞争，因为他们需要更安全稳定的环境养育后代。群体的权利交替并不是瞬间完成的，在鲁伊特接替耶罗恩时花了2个多月的时间。这2个月两只黑猩猩不停的争斗、和好，而雌性黑猩猩会在调节过程中扮演重要角色。雌性会主动与他们两个拥抱，在冲突对峙时打破紧张的气氛，极力促成他们和好。&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="#%e6%9d%83%e5%8a%9b%e4%b8%8e%e7%9a%84%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e7%bb%93%e5%b0%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;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%ae%87%e5%ae%99%e5%ae%89%e5%85%a8%e5%a3%b0%e6%98%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本文大段内容都取自《黑猩猩的政治》一书，不代表个人想法。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《三国演义》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89/</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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;提起《三国演义》似乎每个人都可以说几个其中的人物、情节，但是你真的看过《三国演义》原著吗？&lt;/p&gt;
&lt;p&gt;本身很喜欢三国题材游戏，一些游戏比如《霸王大陆》《全战三国》等等都是我的最爱，很喜欢收集名将大杀四方的感觉。但是回想起来我似乎没有完整读过《三国演义》，有些全战中的大众脸将领都不知道是谁。而此时想想，似乎没有一个小说能跟《三国演义》相提并论的，所以就抱着试一试的态度翻看了原著，结果一发不可收拾···&lt;/p&gt;
&lt;p&gt;《三国演义》是古代的白话文，跟现在的普通话白话还是有些区别的。比如”暗赍金帛，结交中涓封谞“，意思是偷偷送金银帛布，结交宦官封谞（赍ji一声，带的意思，常考；中涓是一种近侍官职，后世直接指宦官）。刚开始读确实有些不习惯，但是看久了就很顺畅了，有些不懂的看看注释或者划线就行（再次感谢电子书）。另外，阅读建议跳过前言，建议屏蔽关键词“农民起义” 、“辩证”、“封建”···&lt;/p&gt;
&lt;p&gt;很多人把《三国演义》跟《三国志》混淆，再次特别强调：&lt;strong&gt;《三国演义》是小说，《三国志》是正史&lt;/strong&gt;。有些人可能会说，“《三国志》也是私人撰写的”，或者“历史本没有真相”等等言辞。你可以认为历史没有真相，但是如果把这句话带入历史研究，那么就不需要研究历史了。正史也不是所有描述都是精确的，有些正史同样有模棱两可相互矛盾的描述，但只会影响它的历史参考价值，而不会剔除它正史的标签。《三国志》是二十四史之一，名正言顺毋庸置疑的正史！《三国演义》是深度参考了《三国志》并在其上进行了艺术加工所著作而成的小说。&lt;/p&gt;
&lt;p&gt;本篇只要不提及《三国志》都是以小说来聊的。虽然看了一点《三国志》（看了一点发现全战主要参考的是《三国志》👍），但感觉太硬核了，决定放弃。总之，小说的人物、情节都有艺术加工，跟历史有差别，请各位读者注意区别···



&lt;img src="https://lastdba.com/img/csdn/86043abcfb26.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="#%e8%b5%a4%e5%a3%81" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;其实三国中有很多情节都值得拿出来聊一聊，奈何篇幅有限（实则不想写了），情节这里只聊聊赤壁。&lt;/p&gt;
&lt;p&gt;赤壁之战必为演义之绝，各个名角悉数登场，计谋百出，周瑜与孔明的智斗也更突显智斗巅峰。我本来很喜欢周瑜这个角色，才华横溢、飒爽英姿、有勇有谋、调兵遣将、年前有为、（人生赢家），本身也有王佐之才，但是小说为了突显诸葛亮的计谋，故意将其才华处处放在孔明之下，赤壁之战的绝对主角以衬托诸葛亮。我在看电视剧、小说的时候，愈发觉得前期诸葛亮确实是个“妖怪”，“完全非人”。&lt;/p&gt;
&lt;p&gt;赤壁之战可谓巨星云集，刘备的三大军师其实都有参与其中，诸葛亮、庞统（当时在东吴）、徐庶（当时在曹营）均在赤壁计谋的重要环节武将基本只是捡人头，只有刘备、关羽去过东吴水寨，赵云搭救过军师。东吴本身是主角自不必多说，周瑜、鲁肃、黄盖、甘宁、阚泽都是重要戏码，其余武将同心同德没有一个拉胯的。曹操这边，曹丞相本尊、程昱、荀攸谋士（荀彧、贾诩没来，郭嘉早夭），武将毛玠、于禁，一些张辽、许褚等名将打酱油，还有大冤种蔡瑁、张允、蔡中、蔡和，小丑蒋干等等。我想应该很多人没有仔细阅读过赤壁之战，或者根本没有读过原著，我刻意画了个流程图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/272e97875e57.png" alt="在这里插入图片描述" /&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="#%e5%8a%a0%e6%88%8f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在原著上添加自己的各种理解或者剧情，我称之为加戏。原著剧情也就非常精彩了，即便是对于现代人来说不理解，但是带入古代（东汉！）人的思维，基本没有逻辑不通顺的地方，这也是三国演义为什么评价如此高的原因之一。所以，有很多人还是喜欢尊重原著的电视剧老版三国（改的极少），而不是加戏的新版三国。有些加戏也不知道是谁说的，阴谋家很多，很多加戏剧情已经被大众熟知，属实可惜。&lt;/p&gt;
&lt;p&gt;孔明放曹操。华容道义释曹操时，孔明是故意让关羽放曹操逃走。这里有太多的解读。而原著中放曹操逃跑，只是因为孔明夜观星象认为曹操今晚不会死而已。不要以为这很儿媳，三国演义中对“观星”这种玄幻设定是&lt;strong&gt;非常肯定&lt;/strong&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="#%e7%8e%84%e5%ad%a6" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;毕竟是小说，许多情节是戏剧化后而加入的（《水浒传》等也是如此），为了阅读的愉悦性来一点艺术加工是“画龙点睛”而不是“画蛇添足”。我个人更愿意把《三国演义》当成玄幻小说来看，而不是历史小说。&lt;/p&gt;
&lt;p&gt;黄巾起义。黄巾起义与其说是农民起义，不如说是宗教战争。刚开始看到张角用符水可以治病，我以为作者想表达黄巾军不服教化装神弄鬼，后来发现于吉也用符水治病，于吉明显是正面角色，因孙策不信反把小霸王给玄幻死了。所以符水治人对于作者来说是没问题的，张角三兄弟确实有玄幻能力，黄巾军基本都是教徒。我后面也接受了符水治人这个设定。&lt;/p&gt;
&lt;p&gt;“两耳垂肩，双手过膝，目能自顾其耳”。双手过膝也就算了，目能顾其耳，这应该不是眼睛的问题，是耳朵的问题，可能是个大象吧···&lt;/p&gt;
&lt;p&gt;杀妻而食。刘备逃难求食物，遇到一个猎户，没有寻到野味，乃&lt;strong&gt;杀妻而食&lt;/strong&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="#%e7%bc%ba%e9%99%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e4%ba%ba%e7%89%a9%e4%bc%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;锐评几个人物，简单介绍和总结人物，及其重要事迹。虽然不太符合演义的思想，但人们总是津津乐道武力值和智力值，通读过演义后在这里也尽量聊聊数值。&lt;/p&gt;
&lt;p&gt;其中，solo的武力值不是看谁打败谁，三国演义中很多都是平局，或者因为什么事战二三十合就跑了，我是以交战回合数算，三国演义中一般最高100回合是极限，也可能休息后再战100回合的，如马超许褚等。&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%ad%8f%e6%96%b9" 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;/p&gt;
&lt;p&gt;郭嘉：无槽点，占地军师no.1，考的是智力而不是玄幻，受人喜爱。跟随曹操征北方时病死。赤壁曹操败后，哭奉孝不在，其余人汗颜。&lt;/p&gt;
&lt;p&gt;程昱：前期出场非常多的谋士，智力值比较高，个人感觉智力水平应该跟曹操差不多，顶级，但低于荀彧郭嘉。赤壁之战能看穿东南风，但被曹操说服&lt;/p&gt;
&lt;p&gt;贾诩：李傕的谋士，后投靠张绣，后降曹，曹中期重要谋士。&lt;/p&gt;
&lt;p&gt;许褚：魏方顶级solo战神。一回合活捉何仪，跟马超打200回合，裸衣战神。汉中之战时，因喝酒运粮反应慢，被张飞刺中肩部，后面戏份不多了。&lt;/p&gt;
&lt;p&gt;典韦：魏方顶级solo战神，善使双戟，与许褚大战两个时辰。感觉像曹操的亲卫。张绣叛变时被杀，战绩不多&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;p&gt;曹冲：演义未提及&lt;/p&gt;
&lt;p&gt;曹仁：带兵大将，无solo，守城一绝。守南郡（军士）射中周瑜，守樊城（军士）射中关羽。曹丕时期亡。&lt;/p&gt;
&lt;p&gt;曹洪：常带兵出现。与何曼战五十合，单杀何曼。单杀袁谭。危机之下救曹操，与马超战五十合，刀法散乱，气力不如。与曹休逼迫汉帝退位，后面无出场。&lt;/p&gt;
&lt;p&gt;夏侯惇：刚猛，拔矢啖睛。与高顺战五十合，胜。过五关斩六将，单搦关羽被张辽打断。博望坡魏军主角。曹丕时期病死。&lt;/p&gt;
&lt;p&gt;夏侯渊：千里袭人（没找到原文）。带兵戏份多，领军型将领，后在定军山被黄忠所杀。&lt;/p&gt;
&lt;p&gt;张辽：五子良将之首。以前是吕布部下，与关羽交厚。带兵一等，solo还行。随曹丕战东吴时，被东吴将领丁奉射中其腰而死。&lt;/p&gt;
&lt;p&gt;张郃：五子良将。官渡之战被郭图陷害，投靠曹操。败于张飞（阆中张飞墓还能看到张飞题的“大破张郃部”），看上去只能跟张飞打几十回合，solo一般，带兵一等，前期戏份较多。后因追击过深，被孔明乱弩射死于剑门关。&lt;/p&gt;
&lt;p&gt;徐晃：五子良将。戏份巨多，根本说不完。李傕郭汜之乱时，在杨奉手下，后投靠曹操。与许褚交五十合，solo还行。与关羽也交厚（颜良文丑时，张辽徐晃出战不利，关羽上去一刀一个，应该是此时交厚···），与曹仁合力击败关羽荆州军。后孟达复叛，被孟达射中头额而死。&lt;/p&gt;
&lt;p&gt;乐进：五子良将。戏份也很多，常带兵出现。与吕布部将臧霸战三十合，与凌统战五十合，solo一般。曹操合孙权战与合肥时，跟凌统solo，曹休把凌统射下马，甘宁一箭射中乐进面门，随后再也没有出场，也不知道是医没医好。&lt;/p&gt;
&lt;p&gt;于禁：五子良将。张绣叛变时，人言于禁造反，于禁没有先自我澄清，而是安营拒敌，被曹操赞赏。樊城被围时，领军支援，怕庞德抢功各种小动作，屯军不利，关羽水淹后被擒而后投降。吕蒙攻下荆州后把牢里的于禁放回魏国，后被曹丕不耻，郁郁而终。&lt;/p&gt;
&lt;p&gt;庞德：之前在马超手下，异常骁勇，个人很喜欢的角色。抬着棺材出征，能和关羽打100回合，solo界最高礼遇，名气不如五虎将、许褚、典韦，但个人认为solo武力值应是同一水平，可惜没有被重用。随后被猪队友于禁拖累，被关羽水淹七军而被抓，不服关羽，不降被杀，真英雄。&lt;/p&gt;
&lt;p&gt;李典：前中期常带兵出现，生擒黄邵。solo：与赵云交锋，约战十数合，料到不过，拨马回阵。合肥大战后没再出现。&lt;/p&gt;
&lt;p&gt;甄姬：袁熙的老婆，袁绍兵败后，曹丕抢过来当了皇后。&lt;/p&gt;
&lt;p&gt;司马懿：后期神级占地军师，会观星，甚至能提刀solo，与诸葛亮在汉中附近打的由来有回，大战略没有输过亮。后夺曹爽兵权，魏国司马家掌权&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;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%9c%80%e6%96%b9" 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;张飞：张飞是特别脸谱化的角色，但是他的战绩比关羽好。环眼贼，有勇有谋，嫉恶如仇，真性情。全三国唯一一个敢叫嚣吕布的人，跟吕布可以打100回合，长坂坡喝退曹军，陆路入蜀，义释严颜，大破张郃，刺伤许褚。能带兵，能solo，有智谋，三国顶级武将。有一幕特别令人感动，关羽死后，刘备迟迟不发兵复仇，张飞对刘备说，**兄弟都没了，皇帝有什么好做的？**你不给兄弟报仇，以后就不要来见我了👍。之前去过阆中张飞墓，张飞写的字特别俊秀，并没有五大三粗的感觉···&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;p&gt;赵云：solo没有输过，都没有能跟他打100回合的人物，基本上去就是“一枪搠死”。闪避拉满，“昔日长坂坡英雄尚在”。带兵不多，比较像刘备亲卫，保护宗室。刘备称其为兄弟，但是没有进入核心三人组。&lt;/p&gt;
&lt;p&gt;黄忠：长沙与关羽斗100回合，马失蹄被关羽放了，后不搭箭而射，报答不杀之恩。汉中之战斩杀夏侯渊。&lt;/p&gt;
&lt;p&gt;马超：锦马超。操：“马超之勇，不下当年吕布”，差点杀得曹操割须弃袍，操被曹洪所救。与顶级战力许褚、张飞各打200合。性急且残暴，有屠城行为。在刘备手下战绩不多&lt;/p&gt;
&lt;p&gt;魏延：脑后反骨。中后期蜀国重要将领，solo还行，带兵一流。诸葛亮料定亮死后魏延必反，被马岱所杀。子午谷奇谋，虽然司马懿夸过，个人认为有点扯&lt;/p&gt;
&lt;p&gt;严颜：solo能力基本为0，被张飞暴打。射箭能力顶级，射中张飞头盔。参加过汉中之战，后面无出场。&lt;/p&gt;
&lt;p&gt;黄月英：其实没有什么戏份，只是在介绍诸葛亮之子诸葛瞻时，描述过此人：“母貌甚丑，而有奇才，上通天文，下察地理，凡韬略遁甲诸书，无所不晓”&lt;/p&gt;
&lt;p&gt;诸葛瞻：武侯之子，出场尬吹一波，出征邓艾，被邓艾所杀。&lt;/p&gt;
&lt;p&gt;刘封：刘备义子，solo能力低下，无计谋，易被说服，副作用。关羽不喜欢此人，后来关羽兵败求救，刘封孟达不发兵，导致关羽遇害。随后被刘备斩掉。&lt;/p&gt;
&lt;p&gt;孟达：叛了又叛。关羽之死有锅。唯一高光，射杀徐晃。后被司马懿杀掉。&lt;/p&gt;
&lt;p&gt;刘备夫人：甘夫人，长坂坡投井的那个，阿斗的亲母；糜夫人，刘备在荆州时去世，因此东吴求亲；孙尚香，50多岁老牛取了个16岁左右的姑娘；···&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;p&gt;张苞：张飞亲子。中后期大将，与关兴同出场&lt;/p&gt;
&lt;p&gt;廖化：本来是黄巾，后来追随关羽。败走麦城时，跑出去拉救兵，没有被杀。后面出祁山有出场。&lt;/p&gt;
&lt;p&gt;周仓：本来是张宝部下，后来追随关羽，给关羽拿刀。与赵云交战连败，身中三枪，solo不太行。关羽死后自杀&lt;/p&gt;
&lt;p&gt;马岱：后期蜀国将领，出场较多。攻南蛮、出祁山都有功，受丞相锦囊计斩杀魏延&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="#%e5%90%b4%e6%96%b9" 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;/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;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;/p&gt;
&lt;p&gt;周泰：为救孙权，杀进杀出。每有一处伤口，孙权罚一杯酒。&lt;/p&gt;
&lt;p&gt;潘璋：战关公，只三合，潘璋败走。关羽显圣，被关兴所杀&lt;/p&gt;
&lt;p&gt;丁奉：射杀张辽。后期吴国重要将领，活到第119回合&lt;/p&gt;
&lt;p&gt;马忠：潘璋手下。很多人没有听说过这个角色，但是关羽、黄忠都是他杀的。杀关羽算是捡人头，杀黄忠是真实力，一箭射死善射的黄忠。后被糜芳刺杀。&lt;/p&gt;
&lt;p&gt;蒋钦、韩当、徐盛···：太多了，不突出，记不住。&lt;/p&gt;
&lt;p&gt;孙尚香：正史中没有孙尚香这个角色。小说中孙尚香只有人物刻画，喜欢舞刀弄剑，她没有真正参加过战斗，跟刘备结亲后没有子嗣，后来被骗回东吴，再没有跟刘备见过面。但是后世很喜欢孙尚香，是一个人气角色。全战颜值担当：



&lt;img src="https://lastdba.com/img/csdn/b103703b92df.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%85%b6%e4%bb%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;吕布：三国第一勇夫。前期没人可以solo，只有多打一才会败（吕布的后期solo过张飞）。曹操当年在吕布这里吃过亏，最终曹操是大赢家。&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;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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;能聊的实在太多了，以为2、3个小时能写完本篇，结果时间成本翻了几倍。《三国演义》确实很精彩，非常值得一读（这不是废话吗），《三国志》估计不会继续翻看了，要赶紧开启下一篇章···&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《杀死一只知更鸟》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E6%9D%80%E6%AD%BB%E4%B8%80%E5%8F%AA%E7%9F%A5%E6%9B%B4%E9%B8%9F/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E6%9D%80%E6%AD%BB%E4%B8%80%E5%8F%AA%E7%9F%A5%E6%9B%B4%E9%B8%9F/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c301867ed363.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《杀死一只知更鸟》这本书应该很多人都知道，我看评分实在是太高了，也是忍不住拿起来读一读，果然故事很精彩，不会有无聊的感觉。跟我之前看的几本书的风格差的还是挺远的，个人觉得很适合“中学生”阅读（无偏见），简单有趣又写的非常好的故事。其实整本书想表达的东西很明显：不要伤害无害的人。怎么基于这个简单的思想写出精彩的故事，才是最难的。&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c301867ed363.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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="#%e6%96%87%e7%ac%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;个人认为《知更鸟》这本书最棒的地方就是文笔。作者把美利坚偏远小镇的故事写的很传神，几个故事描写的很惊艳，剧情也是随着时间线走的，不会有乱七八糟的感觉，读起来很顺畅舒适。故事从开头就埋下伏笔，直到最后才把这个最大的伏笔挖出来。对于白人和黑人的生活差别描述的也很传神，这本书的故事跟我之前看的美剧《大西洋帝国》时代相当，电视剧里也有黑人社区的样子，所以这里我自己倒是很好想象出白人、黑人社区的场景来。
其中有一段主角被揍的情节印象非常深刻，“我一下子被摁在地上，眼前是一只小蚂蚁，正在草丛里费劲儿地搬运面包渣”。我很难说清楚这段话到底是什么含义，正在被揍，却关注起了蚂蚁搬运面包渣？或许没有含义？但是无论怎样，这个描写几乎让大部分人都会画上重点，画面感太强了。而且很像长时间沉浸于紧绷的工作时出来抽根烟的感觉···把你从紧张的剧情突然带入到另一个安静的世界又马上回去。
还有一个首相的故事印象也很深，年幼的女主问他爸爸：“什么是‘婊子’？”，他爸爸给他讲了一个首相吹羽毛的故事，“首相每天坐在众议院里朝天上吹羽毛，使出浑身解数不让羽毛飘落下来，可是他周围的人一直不断地掉脑袋”。当时看到这里我跟女主一样是懵逼的，这都是哪跟哪呀？最后靠着百度才弄明白。他爸爸的意思是，不要在乎无关紧要的事，其实也就是他爸爸没有任何解释。但是到最后强奸案公开审理时，年幼的女主是明白的，她知道rape是什么意思。很难说这种顾左右而言他的教育是不是对的。&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%b0%a4%e5%8e%84%e5%b0%94%e6%98%af%e8%b0%81%e6%9d%80%e7%9a%84" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;最后几章描述的非常精彩，我在阅读的时候感觉自己完全已经融入到当时月黑风高的操场，婊子养的尤厄尔（这是书里警长对尤厄尔的称呼，我第一次读到这里的时候心理也骂了一句···）追杀两个无辜的小孩···最后尤厄尔死了，整个事情的真相却并不十分清晰，剧情以主角小女孩为第一视角描述，但是她并没看到尤厄尔是被谁杀死的。
因为我读的是电子版的，可以看到很多读者的注解评论，我发现很多人完全没有搞清楚整个案件的关键细节，我第一遍读完也是非常懵逼，反复看了好几次，总算弄清楚了写作的用途和案件的始末。我从几个关键问题出发来解开这个谜底。
&lt;strong&gt;1).怪人拉德利是黑人还是白人？&lt;/strong&gt;
这个问题看似很扯但很重要。如果拉德利是黑人，那么前面的汤姆·鲁滨逊就是前车之鉴，一个黑人杀死一名白人够死好几回了，陪审团不在乎真相是什么，被告是黑人就足够宣判有罪。所以，老父亲和老警长想保护拉德利是理所当然的，把拉德利放在案子里不过是妄送一个好人的性命。这也会使这部作品是一个黑人种族主义相关的著作。
但是拉德利是个白人，所以上面的想法都不成立，这也让著作内容更符合标题。拉德利是白人作者没有直接交代，但可以这么说，只要作者没交代是白人，那么他就是白人~。当然还有其他线索，例如：拉德利小时候跟坎宁安（白人）小孩厮混、住在白人小区、他的皮肤是惨白的···拉德利是全文从始至终都在描写的人物，也是最为浓墨重彩描写的“知更鸟”，但是在最后两章才见到其真容，所以我一直不确定他是白人让我非常难受···
&lt;strong&gt;2).案件的真空期&lt;/strong&gt;
下面一段是小女主角被尤厄尔制住，最后被反杀的描写：
“把我勒得渐渐喘不上气，根本动弹不得。突然，他被人从身后猛地一扯，扑通一声摔在地上，差点儿把我也带倒了。我心想，是杰姆爬起来了。
有时候，人的反应很迟缓。我呆呆地站在那里，像个哑巴一样。厮打声慢慢停息了，有人在呼哧呼哧喘气，夜晚又恢复了先前的沉寂。
&amp;hellip;我慢慢意识到，此时树下有四个人&amp;quot;
从尤厄尔被拉开到树下四个人，经历了一场打斗，随后：&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;li&gt;女主傻站着，惊魂未定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;真空期就是指谁尤厄尔拉开，并把他杀了，到底发生了什么？后面老父亲阿迪克斯和警长的复盘就围绕这个真空期展开。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3).厨刀&lt;/strong&gt;
首先，警长用来演示的刀是弹簧刀，不是厨刀。“尤厄尔是被这把刀杀死的吗？”“不是，那把刀还插在他身上。从刀柄看是把厨刀”。所以警长没有销毁作案凶器的事实。
任何杀人案件的作案凶器都是极其重要的关键证据。很明显，这把厨刀是杀人凶器，谁带来的这把厨刀，很有可能就是杀人凶手。警长说“尤厄尔可能是在垃圾场的什么地方见捡到了那把厨刀，磨得贼快···尤厄尔是自己倒在刀口上的”，这是警长的主观猜测。其实有很多种可能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;尤厄尔带来的刀，自己把自己绊倒，厨刀插入肋部意外死亡&lt;/li&gt;
&lt;li&gt;尤厄尔带来的刀，被断臂吉姆抢了过来反杀&lt;/li&gt;
&lt;li&gt;拉德利带来的刀，杀了尤厄尔&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;首先，尤厄尔带刀来的概率很低，他如果带刀来，直接冲上来捅就完了，不需要扭断吉姆的手臂再把女主掐死这么费劲。然后再来&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一种情况，尤厄尔已经跟人打起来了，虽然没有明示是跟谁打。这个时候意外死亡有点扯，但确实也不能完全排除这种情况，虽然概率极低。&lt;/li&gt;
&lt;li&gt;第二种情况，断臂吉姆抢刀反杀，这个情况是建立在女主说“感觉是吉姆把尤厄尔往后一扯”，所以理所当然应该是断臂吉姆跟尤厄尔打斗。女主没有看到谁扯的尤厄尔，她只是说感觉是他。一个刚被扭断手臂的十三岁小孩夺刀反杀成年人，这种情况的概率也极低&lt;/li&gt;
&lt;li&gt;第三种情况，拉德利带来的刀，把尤厄尔往后一扯中断尤厄尔掐死女主，然后拿刀直接杀了尤厄尔。这是最有可能，但是是老父亲和警长复盘“刻意”没有提及的情况。有个细节可以支持这个情况：在尤厄尔冲出来前，两个小孩大喊过，周围邻居应该没有听到，但是前文提及案发现场那棵树离拉德利家非常近。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;4).复盘过程&lt;/strong&gt;
无论是从著作的目标、氛围，还是具体的案件分析，基本可以锁定杀死尤厄尔的人是怪人拉德利先生。
父亲和警长的复盘对话我反复阅读，非常有意思。它描写了整个案件的反复推论尤厄尔的死亡过程，以及父亲警长的心理变化的过程，但是又全程不提及真正的杀人凶手！&lt;/p&gt;
&lt;ol&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;li&gt;点题
“这个人为你、为整个镇子做了一件大好事儿，如果人们无视他的隐居习惯，硬要把他拉到聚光灯下——我认为，这就是犯罪” 这句话直接点题了。知更鸟是无害、纯真的人的象征，把拉德利这只知更鸟拉到聚光灯下是犯罪，对应了父亲阿迪克斯先前说的话：“要记住一点，杀死一只知更鸟便是犯罪”&lt;/li&gt;
&lt;/ol&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《杀死一只知更鸟》是一个比较简单的故事，容易被人理解，至少相对于我之前读的一些书来说是这样的。书中知更鸟们的故事令人影响深刻，让我想起几年前的社会人龙哥被反杀的事件。如果没有龙哥，大概我们的也是正当防卫致人死亡还要判刑的吧。想想差不多100年前的美国，那个时候法律本身才刚刚建立不久···想想那个被叛了冤案的黑人，在狱中想要逃脱而被狱警用枪打死，他在当时狱中是怀着多么绝望的心情，只是想做一个不坏的人，人生就这么突然结束了。
用文中的父亲阿迪克斯的一句话来结尾：“我认为世界上只有一种人，那就是人”。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《太空漫游》系列</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%A4%AA%E7%A9%BA%E6%BC%AB%E6%B8%B8%E7%B3%BB%E5%88%97/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E5%A4%AA%E7%A9%BA%E6%BC%AB%E6%B8%B8%E7%B3%BB%E5%88%97/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b4ea64acd991.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;科幻迷绕不开的作品，阿瑟克拉克的经典著作——《太空漫游》系列。《太空漫游》总共有4部，分别是《太空漫游2001》《太空漫游2010》《太空漫游2060》《太空漫游3001》。从名字也能知道，对未来的科技幻想分别发生在相应的年份。不要以为2001已经过去了，作者在著成《2001》的时候是1968年！至少我无法想象30年后的这个世界是什么样子的，人类又把太空探索进行到了什么程度。
我之前看过《2001》后就写过一篇读后感，并且着迷于《2001》的设定、精彩的太空剧情、奇幻的宇宙背景···随后立即开始拜读后面3部作品。刚开始还以为会把背景设定越写越大，然而并不是···后3部的故事还是在木星-地球之间的这个宇宙维度，已经非常非常小了，后面更多的是填充一些剧情和想象，并把整个故事讲述完整。&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/b4ea64acd991.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;科幻迷绕不开的作品，阿瑟克拉克的经典著作——《太空漫游》系列。《太空漫游》总共有4部，分别是《太空漫游2001》《太空漫游2010》《太空漫游2060》《太空漫游3001》。从名字也能知道，对未来的科技幻想分别发生在相应的年份。不要以为2001已经过去了，作者在著成《2001》的时候是1968年！至少我无法想象30年后的这个世界是什么样子的，人类又把太空探索进行到了什么程度。
我之前看过《2001》后就写过一篇读后感，并且着迷于《2001》的设定、精彩的太空剧情、奇幻的宇宙背景···随后立即开始拜读后面3部作品。刚开始还以为会把背景设定越写越大，然而并不是···后3部的故事还是在木星-地球之间的这个宇宙维度，已经非常非常小了，后面更多的是填充一些剧情和想象，并把整个故事讲述完整。&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%9b%9b%e9%83%a8%e6%9b%b2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;《太空漫游2001》
 &lt;div id="太空漫游2001" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%a9%ba%e6%bc%ab%e6%b8%b82001" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;看完整个系列，仍然感觉这一部是最经典的。可能是这一部的剧情跟库布里克讨论的结果···
因为之前写过一整篇读后感了，所以不再赘述。感兴趣的朋友可以看下往期&lt;a href="https://mp.csdn.net/mp_blog/creation/editor/130515764" target="_blank" rel="noreferrer"&gt;读书笔记——《2001太空漫游》&lt;/a&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;《太空漫游2010》
 &lt;div id="太空漫游2010" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%a9%ba%e6%bc%ab%e6%b8%b82010" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这一部也很精彩。原著中以“钱学森号”命名了天朝发射到木星进行探索的宇宙飞船，并且“钱学森号”是人类第一次载人登录探索木星的卫星——欧罗巴，抢在了美国人的前头！虽然结果不太好，不过剧情很精彩~“钱学森号”出事前，宇航员描述了欧罗巴的低等生命体，并最终被“外星生物”袭击而遇害。这个”失事“的情节令人引发无限的遐想，欧罗巴上到底有什么生命？我们人类又该做什么呢？
最后木星上的”石板“经过一系列自我复制，最终把木星变成了白矮星！木星被点亮了！从此天上有两个”太阳“。这个设定太棒了~&lt;/p&gt;

&lt;h3 class="relative group"&gt;《太空漫游2060》
 &lt;div id="太空漫游2060" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%a9%ba%e6%bc%ab%e6%b8%b82060" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这部作品感觉有点赶工，主要是因为哈雷彗星要来了~克拉克在序言中写到，因为哈雷彗星马上要掠过地球，如果再不出作品，对哈雷彗星的探索剧情可能就会不合时宜了。是的，这部大篇幅的在写探索哈雷彗星，有一些木星的剧情但对整体主线剧情推动影响不大。
哈雷彗星每76年绕太阳一周。下次回来还有40年的时间（2061年7月28日）。算来上次近日点也差不多是作成时，整个社会都在讨论哈雷彗星。（能感觉到这几年没人提这事儿了）&lt;/p&gt;

&lt;h3 class="relative group"&gt;《太空漫游3001》
 &lt;div id="太空漫游3001" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%e7%a9%ba%e6%bc%ab%e6%b8%b83001" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;完美的收官之作！这个收官影响了无数的科幻小说，甚至能够明显感觉到《三体》的影子。
前三部作品都还在21世纪，《3001》直接跳跃了1000年！人类通过”脑机“来灌输知识，而不是学习，太空旅行的速度也大大提升···
但是说实话，1000年呀，1000年人类才进步到这种程度我更愿意相信是智子的缘故。啊？难道说老刘的智子就是这个思路？
这部最为精彩的还是人类复活了普尔——一个在第一部中被哈尔杀死的宇航员。如果不提起这个人，大家都还以为他还飘在太空里···复活普尔不仅把第一部的剧情进行呼应，还能以一个”古代人“的身份观察并揭开3001年的人类世界。&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%89%e4%bd%93%e7%9a%84%e5%bd%b1%e5%ad%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;li&gt;外星生命即将来袭。我们有时间喘息，但是好像又没有什么用&lt;/li&gt;
&lt;li&gt;抵抗计划。外星生物就要来临，人们开始了抵抗计划，此时人类还不知道我们面对的敌人是究竟什么样子&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实两部作品许多地方有大的不同，比如太空漫游是写宇宙探索的，而三体是整个人类社会面对外星文明；太空漫游主角其实就几个，哪怕过了1000年，而剧情也主要都是围绕着木星写的，三体的场面更宏大，人物也更多···&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;终于把《太空漫游》四部曲看完了，确实能感觉出它是科幻小说的巨作，它满足了科幻迷对“探索”太空的向往。在宇航局还没有开始探索到“那里”时，阿瑟克拉克先到了那里。甚至NASA的宇航员会跟克拉克回信“我们拍到了月球背面，那里没有石板、没有异常”，还像是在说“你这个骗子，我就是因为看了你的著作才去的！”，哈哈~
克拉克在小说中写了很多“钱学森号”的剧情，并在几部著作后面都反复说到钱学森是一个对航天业影响很大的人，无论在中国还是美国。美国以莫须有的罪名将其逮捕，而钱学森最终回到祖国从零开始做航天并影响了导弹制作。克拉克在一次北京之旅中还特意去拜访钱学森，但当时钱老的身体不好医生不让访问，克拉克把自己签名的太空漫游托人送转给了钱老。
观看完整个系列，能感受到当时人们对宇宙探索的痴迷。但是随着阿波罗计划关闭，人们似乎再也没有关注过太空探索，不过随着马斯克的火星殖民计划，“太空”这个主题似乎又回到了人们的视野。NASA说2040年要登录火星，不知道真的假的，到时候来挖坟。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《万智有灵》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E4%B8%87%E6%99%BA%E6%9C%89%E7%81%B5/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E4%B8%87%E6%99%BA%E6%9C%89%E7%81%B5/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/921a326cbe1c.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;上一本书是《走出荒野》，太平洋步道女王提到了这本书《万物有灵》，她同样是看一点撕一点的阅读。我想，在她穿越山河森林，听见鸟鸣溪流的旅行过程中，是不是看这本描写动物有如何聪明的书——《万物有灵》，会特别有感觉？
我之前看过《人类简史》（还是忍不住想要安利这本书太棒了），这本书从人类开始直立行走讲起，直到人类慢慢成为神···。到底是什么导致人类与众不同，可以从万千生物中脱颖而出？
作者，弗朗斯·德瓦尔，是猿类行为领域的专家，这个领域在所有种类的动物行为中也是最前沿、最热门的。特别是随着人们完善实验方式，我们发现人类那些“不停”自诩独有的特性，在其他动物群体中均被发现存在。&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/921a326cbe1c.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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%8c%a9%e7%8c%a9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本书是一本非常具有科学性的书籍，其中有大量的实验、观察、生物科学发展过程的描述。既然是科学，我们来学点东西~当你在看到猩猩这个词汇的时候，你想到的是什么样的猩猩画像？无论你想到的是什么，都不够准确。因为猩猩是一个统称，可以粗略地把猩猩分为4种：黑猩猩、大猩猩、红猩猩、长臂猿（倭黑猩猩应该黑猩猩中的一支，书中常提及，为了方面理解这里忽略）：&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;th&gt;长臂猿&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Homo Sapien&lt;/td&gt;
 &lt;td&gt;chimpanzee&lt;/td&gt;
 &lt;td&gt;gorilla&lt;/td&gt;
 &lt;td&gt;orangutan&lt;/td&gt;
 &lt;td&gt;hylobates&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;img src="https://lastdba.com/img/csdn/f164979861f5.png" alt="点击查看图片来源" style="zoom:180%;" /&gt; /&amp;gt;&lt;/td&gt;
 &lt;td&gt;&lt;img src="https://lastdba.com/img/csdn/d7747bc5f86e.png" alt="点击查看图片来源" style="zoom:80%;" /&gt; /&amp;gt;&lt;/td&gt;
 &lt;td&gt;&lt;img src="https://lastdba.com/img/csdn/6e6713e61e0e.png" alt="点击查看图片来源" style="zoom:160%;" /&gt; /&amp;gt;&lt;/td&gt;
 &lt;td&gt;


&lt;img src="https://lastdba.com/img/csdn/0e9a9c47a115.png" alt="img" /&gt;&lt;/td&gt;
 &lt;td&gt;&lt;img src="https://lastdba.com/img/csdn/7837fde1fba6.png" alt="点击查看图片来源" style="zoom:180%;" /&gt; /&amp;gt;&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/4ea31e990816.png" alt="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Hominoid_taxonomy_6.svg/800px-Hominoid_taxonomy_6.svg.png" /&gt;
Hominoidea是人科的意思，是的没错，这些我们人类的近亲都属于人科！其他几个Homixxx是几个族系小分支。从上面的家族图谱可以看出，我们智人和黑猩猩是亲缘最为接近的，大猩猩、红猩猩、长臂猿亲缘关系渐远。&lt;/p&gt;
&lt;p&gt;演化时间：



&lt;img src="https://lastdba.com/img/csdn/966725f9850f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;在大概600万年前，我们跟黑猩猩还是同一物种···黑猩猩也是公认最为聪明的动物。我们真是猴子变的吗？其实这个描述不太准确。虽然上图没有标记出猴子，再往前推的话肯定是同源的，但这并不代表我们是猴子变的，因为就像黑猩猩一样，我们源自同一祖先，而这个祖先本身已经灭绝了。所以我们不是猴子变的，但我们跟猴子是同一祖先，两个分支而已。“尽管很多时候，为方便起见，我们用“动物”指代非人类物种，但是不可否认，人类是动物中的一种”&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%98%af%e4%bb%80%e4%b9%88%e4%bd%bf%e6%88%91%e4%bb%ac%e4%b8%8d%e4%b8%80%e6%a0%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;使用工具？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在看完《太空漫游》后，我以为人类之所以为人，是因为我们学会了使用工具。从我们在手中握住工具后砸开骨髓，到人类走向太空探索未知，皆是因为我们学会使用工具。但是我们可以很容易从其他动物行为中找到类似的，猩猩会使用树枝吃蚂蚁，也会用树干当梯子马上围墙，甚至他们的拇指与我们一样可以握住东西。使用工具在动物王国中其实很普遍。看起来使用工具并不是我们人类独有的特性，那些同样会这项技能的动物没有繁衍出更高级文明。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;认知革命？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在看完《人类简史》后，有一个观点特别的新颖，我也一度长时间坚信它是正确的，那就是认知革命。其作者认为认知革命是智人与其他动物产生巨大差异的重要环节，认知革命发生在农业革命之前，那时的智人还只会打猎。作者在描述认知革命时有一个经典例子：一个人发现河边有狮子，于是回去告诉群落的其他智人，河边有狮子。此时所有人虽然没有亲眼看到，但是他们大脑中都相信了”河边有狮子“这个概念。这种观念传播形成了后来的宗教、权力、国家、货币、公司等等虚拟概念。《万物有灵》中有一个例子：一只猴子，在被其他两只猴子欺负，当他逃无可逃时，他会发出”有蛇“的叫声（当他们遇到蛇时才会发出这种叫喊），另外两只猴子就会停下来观察到底有没有蛇，当他们确实没有蛇时才会继续追赶。有很多观察表明，许多动物具有通过别人讲述的故事而使自己相信的能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;直立行走？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;直立行走解放了双手，而且头脑也愈加发达。这是《人类简史》中有相关描述的。事实上，两足行走不不像我们想象的那么特殊。倭黑猩猩在草原上可以长期靠双足行走。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;语言？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;语言曾经一度以为只有人类才拥有。我们听不懂动物在说什么，并不代表他们没有简单的语言。动物的各种叫声并不是天生的，一只猩猩与一个群体一起成长，他们的在不同情况下的叫喊声是相似的，如果把这只猩猩放在另一个没有关联的猩猩群体中，人们发现他们的叫喊声完全不同，在很长一段时内，这只猩猩无法融入新的群体，直到它学会了新的叫喊方式。曾经也有人认为语言会影响思考方式。但是要想思考，语言并不是必然的。动物通过不同数字相加的能力曾被认为是依赖于语言的，但是实验中的一只黑猩猩成功将数字相加。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;合作？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;《流浪地球2》中有这样一个剧情：部长展示了一个摔断又复原的智人骨头化石，这说明这个智人受了重伤，如果是其他动物，受伤者会被抛弃，但是这个人得到了别人的帮助并活了下来。合作是我们人类与动物的分水岭吗？黑猩猩群体会帮助没什么行动能力的老年猩猩，给他拿吃的，嘴对嘴的喂水。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;复杂的社会关系？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;黑猩猩不仅知道其他黑猩猩跟自己的关系，还知道乙和丙之间的关系。即便出现不认识的黑猩猩，他们也可以通过其他猩猩对这个黑猩猩的态度，来判断它的社会地位，从而做出不同的行为。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;思考未来？&lt;/strong&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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;先吐槽一下这本书的翻译，突出一个机翻。举个例子：&amp;ldquo;人们认为动物善于学习行为的普遍后果，但无法记住任何特定的联系&amp;rdquo;。直接用中文思维很难理解这句话，完全就是机器翻译的句子。但是用英文思维就特别好理解，这句话是说”人们认为动物善于行为学习并知道其后果，但不知道行为和后果之间有什么联系”（作者在反驳这句话）。&lt;/p&gt;
&lt;p&gt;《万物有灵》这本书有很强的学术氛围感，它使用了大量、可靠的实验和观察，来解释动物的行为本质。阅读这本书有一点点像在看论文，逻辑很严谨，观点也很谨慎。猿类作为动物行为研究的前沿领域，对研究人类行为有非常重要的意义，当然一些其他动物的行为也有些用处。&lt;/p&gt;
&lt;p&gt;书中有很多观点会令人灵光一闪。聪明的汉斯、人类幼崽测试环境与猿类不可能对等、所有脊椎动物的脑都是同源的、猩猩超强的记忆力和逻辑推理能力、猩猩的权利斗争等等。弗朗斯·德瓦尔另一本著作《黑猩猩的政治》已经加入书单···&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《未来简史》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E6%9C%AA%E6%9D%A5%E7%AE%80%E5%8F%B2/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E6%9C%AA%E6%9D%A5%E7%AE%80%E5%8F%B2/</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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《未来简史》是以色列历史学家尤瓦尔·赫拉利的人类简史三部曲之一。三部分别为《人类简史》《未来简史》《今日简史》。其中最为著名的当然是《人类简史》，非常宏大的一本关于人类文明历史的书籍，绝对可以刷新历史观，《人类简史》这本书去年（2022年）硬啃原著给一点点读完了，还是很有成就感的。由于个人实在太爱《人类简史》，《未来简史》这本大佬的续作自然成为我今年最重要的“课外书”。&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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《未来简史》是以色列历史学家尤瓦尔·赫拉利的人类简史三部曲之一。三部分别为《人类简史》《未来简史》《今日简史》。其中最为著名的当然是《人类简史》，非常宏大的一本关于人类文明历史的书籍，绝对可以刷新历史观，《人类简史》这本书去年（2022年）硬啃原著给一点点读完了，还是很有成就感的。由于个人实在太爱《人类简史》，《未来简史》这本大佬的续作自然成为我今年最重要的“课外书”。&lt;/p&gt;
&lt;p&gt;《人类简史》说的是人类的历史，从智人直立行走开始到发射火箭探索星空，我们是怎么走过来。《未来简史》讨论的是人类文明当前的重要议题，以及我们将要去往何方。&lt;/p&gt;
&lt;p&gt;这本《未来简史》很难买到，最后jd买到一个二手的中文图书，来自杏坛梁銶琚中学图书馆 &amp;#x1f604;。翻开书的第一页，一个调皮的中学生留下了一行英文，咱就以这个开头~&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;When facing the ultimate questions of ths chaotic world,we need chinese readers to contribute their wisdom.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/43ce9fb701c5.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="#%e6%96%b0%e8%ae%ae%e9%a2%98" 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%b2%ae%e9%a3%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;随便打开一本历史书，几乎都会读到饥荒的惨状，以及人在饥饿状态下的疯狂行径。这里都不用提其他国家的饥荒事件，最值得一提的其实就是我们中国。从有文字记载开始到20世纪，几千年的中国都一直遭受着饥荒的肆虐。我们一直是一个农业国家，几乎所有人都需要在土地上种植农作物，以养活自己和家人。如果遇到作物收成问题，比如自然灾害（过多或过少的雨水、蝗灾等），或者人为破坏（强盗、苛税、不规律作物等），就会有一些人遇到食物短缺问题。现代绝大部分人并不知道连续多日不进食是什么感觉，虽然我曾经有段时间饿过肚子，我也知道长期处于饥饿状态是一般人想象不到的难受的，但我那时也不至于饿死，然而我们的祖先在面临会饿死这样的状态时，会是怎样绝望的情绪？他们也没有其他解决办法，只有祈求神明赐予来年的风调雨顺和大丰收。&lt;/p&gt;
&lt;p&gt;《纸牌屋》里面有句话令我印象深刻：“20年前，我在中国是买不到糖的，现在我可以在任何地方买到糖”。虽然话很糙，却反应了一个现实：中国人已经摆脱贫困。我们，在中国历史上“首次”不再受饥荒之苦。我们创造了这个经济奇迹，这是一个值得被记录的事情！同样的，人类文明也在最近解决了温饱问题，个别地区的粮食问题几乎都是政治因素导致，而且国际上有足够富裕的资源来应急响应短缺问题。粮食短缺已经不再是人类的议题了。&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="#%e7%bb%86%e8%8f%8c%e5%92%8c%e7%97%85%e6%af%92" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;黑死病：14世纪30年代，黑死病，也就是鼠疫杆菌，造成全球7000万~2亿人死亡，死亡率50%左右&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;西班牙流感：1918年，5亿人感染，5000万~1亿人死亡，死亡率 15%左右&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;天花：1967年感染1500万人，死亡200万人，死亡率15%左右。随后全球接种天花疫苗，1979年，天花病毒被人类消灭&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;艾滋：20世纪80年代暴发，已超3000万人死亡。会破坏免疫系统，目前的药物有效果但不能完美治愈。感染率0.9%，死亡率10万分之1.28。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SARS：2003年，8000人感染，700多人死亡&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;禽流感：死亡人数不足1000人&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;H1N1流感：2009年，7-14亿人感染，约15万-60万人死亡，感染率20%，死亡率约0.02%&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;埃博拉：在非洲多次爆发，死亡率50%以上&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上只有黑死病是细菌类，其他都是病毒类。黑死病过于古老，虽然是细菌，由于当时人类医疗水平落后，人们并不知道是怎么回事，造成了大量的死亡，死亡率奇高。其中天花是人类对抗病毒史的最成功案例，人类通过现代医学——疫苗，直接消灭了天花病毒。可以看出，人类制造出了杀死细菌的silver bullet——抗生素，细菌类的流行病已经没有了。但是对于病毒类的流感，仍然是层出不穷，你方唱罢我登场，没有很好的解决办法，现代医学对于病毒类流行病还有提升空间。病毒类的重大流行病仍然是隔几年来一次，季节性流感也一直伴随着我们从未停息过。&lt;/p&gt;
&lt;p&gt;这类流感大部分都是靠着人类自身的免疫力硬抗，现代医学只有辅助作用（也就是降降体温）。特别是对于人类幼崽，除了出身就要打各种各样的疫苗以外，其余“感冒”都得靠自身免疫硬撑，极少有特效药。幼儿园更像是人类流感与抵抗力试炼场，而不是学习的地方。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新冠：《未来简史》成书于2015年，还没有发生新冠事件。作者对流行病的观点是，“医生可以很快上手并快速发现治疗方式，人们很可能已经战胜了流行病”。不知道尤瓦尔·赫拉利对新冠作何感想。&lt;/li&gt;
&lt;/ul&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="#%e6%88%98%e4%ba%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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="#%e4%ba%ba%e6%96%87%e4%b8%bb%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;p&gt;随着人文主义被更多人接受，人文主义演化出三大分支：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;自由人文主义：“正统”的自由人文主义（liberal humanism），也就是自由主义（liberalism）。个人享有自由，尊重个人选择，每个人的感觉对了就对了。最典型的例子就是自由主义认为选票能代表个人意志。但是这需要一个前提：投票前大家都必须是自己人。例如1861年的美国的南北地区、现在的以色列和巴勒斯坦都不可能通过大家一起投票来解决问题。&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;/ul&gt;
&lt;p&gt;1914年到1989年，三种人文主义掀起了一场信仰之战。自由主义和社会主义联合在二战中击败了纳粹主义。随后自由主义国家和苏联各自拉帮结伙形成冷战 ，在冷战前期一直是社会主义处于上风（这里很推荐纪录片《越南战争》），甚至伯克利大学的学生会把毛主席的红宝书放在床头。接着，一切都变了。苏联解体，许多国家转变了自己的信仰，我们也引入了资本市场，人们更喜欢超市（或者淘宝）和挣钱的公司，而不是分配食品和衣物的制度。自由主义在这场信仰之战中大获全胜，他们甚至自我进化，学习对手的观念和制度，比以往提供更健全的教育、卫生和社会保障，但是自由主义的核心思想没有改变。&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%e6%8d%ae%e4%b8%bb%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;数据主义有以下三个观点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;生物是算法&lt;/li&gt;
&lt;li&gt;智能可以没有意识&lt;/li&gt;
&lt;li&gt;高度智能的算法，比我更了解我自己&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/f11b7c00c9f7.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="#%e7%94%9f%e7%89%a9%e6%98%af%e7%ae%97%e6%b3%95" 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;/p&gt;
&lt;p&gt;从数据主义的角度来看，资本主义之所以赢得冷战，是因为分布式算法的资本主义比集中式算法的苏式共产主义更适合那个时代，更好的数据算法胜出。当年我们选择了拥抱市场经济，放弃苏联式的共产主义，相当于把处理器下放到每个人身上，不再采用单一处理的模式，所以中国特色社会主义在冷战中活了下来，而苏联式单一数据处理模式彻底失败，目前只有极少数集权国家仍在使用这种单一模式，这么多年也没有看到他们什么生产力的进步，这也是“生物是算法”的现实写照。&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="#%e6%99%ba%e8%83%bd%e5%8f%af%e4%bb%a5%e6%b2%a1%e6%9c%89%e6%84%8f%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;首先，我们要搞清楚什么是意识？可能有人会说，“意识是自我”，“意思就是内心的想法”。这都没有科学地回答问题，注意科学是讲客观事实的，主观层面的东西不属于科学的范畴，是神学的范畴。我们不能以主观来解释主观。其实到目前为止人类还没有搞清楚什么是意识。&lt;/p&gt;
&lt;p&gt;如果每个人都是算法，那么其实没有什么“自主意识”的概念，我们可以把我们所听、所闻、所见的“数据”称为输入数据，经过我们生物体的计算而得出反应，做出行动，这就是输出数据。人体本身更像是一个cpu，只是这个cpu也许会自动调节，但即便是调节本身，也需要数据输入，比如学习知识、运动健体。那么“自我意识”在这个过程中扮演怎样的角色呢？我明明可以对某件事做出选择，只要我选择不同就会产生不同的结果，我一定是主观意识的，吗？这个问题可能没有那么好回答。如果假如没有主观意识，它不代表大脑死亡，而是“我感觉不到我”，“我”是否还是会做出不同的选择？&lt;/p&gt;
&lt;p&gt;从生物学的角度来看，意识不过是脑神经的许许多多电流，当“我”做出不同的选择时，也许只是哪个神经末梢多发出了一小段电流而已，“自我意识”没有在这个过程中参与任何角色。如果没有“我”，似乎我身体也可以做到做出不同的选择，只要存放在我身体里的“算法”还存在。如果说“自我意识”是存在的，更像是一种信仰，而不是客观事实，就像相信有上帝一样。最前沿的生物科学表明，意思不过是个体生物算法的附带品，可以看成是一种精神污染。&lt;/p&gt;
&lt;p&gt;然后我们来到了另一个问题，人工智能（AI）有意识吗？如果没有意识，我们可以把他当成智能生物看待吗？人类目前能测试AI有无意识的最好的办法是图灵测试。图灵测试的思路很简单，只要正常人类看不出这个AI是不是人类即可。也就是说，AI聪明到一定程度，我们人类只能认为他是有“意识”的。&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%ae%97%e6%b3%95%e6%af%94%e6%88%91%e6%9b%b4%e4%ba%86%e8%a7%a3%e6%88%91" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;人文主义呼吁我们听从自己内心的真实声音，如果自我都是不存在的，那么还要聆听什么呢？而数据主义呼吁：“聆听算法的意见”，算法比我更了解我。例如，一个女性在相亲的时候，遇到两个男性都感觉比较合适，此时在没有算法加持下，女性会遵从自己内心的声音，选择感觉更对的那个人。此时如果有一个算法，告诉她：”我非常了解你，我知道男性A是你喜欢的类型，你会选择他，但是他最终会让你伤心并离开你。男性B才是合适你的，并且如果你选择B，你也会马上坠入爱河，他会让你拥有长久的幸福，这是一个不会让你后悔的选择。”无论从哪个角度，此时是不是应该听取算法的意见而不是当时那个短暂的感觉？&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%e5%b0%be" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;《未来简史》一如既往的富有内容，新颖强健的观点，包含万象，非常推荐的作品。我在阅读的时候，经常会停下来思考，想想他说的是否符合现现实，是否正确，很多时候我会感到震惊。我以前看书的时候是不会用笔划线的，读这本书的时候我这么做了，看完后发现书中到处都是我画的重点。&lt;/p&gt;
&lt;p&gt;这本巨作内容非常夯实，很多东西都不是本篇能够聊完的。本篇文章写的比较片面，基本都只聊了生产力相关的观点，其实还有其他很多东西很新奇的东西，比如书中关于“幸福度”的观点：“你愿意做一个不开心但富裕的新加坡人开心又贫穷的哥斯达黎加人？”我不知道如何选择。但如果作者换句话问我，“你是想多吃点火锅，还是每天蔬菜粗粮营养均衡保持良好的身体状态？”，那我肯定回答火锅。&lt;/p&gt;</content:encoded></item><item><title>读书笔记——《走出荒野》</title><link>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E8%B5%B0%E5%87%BA%E8%8D%92%E9%87%8E/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E8%B5%B0%E5%87%BA%E8%8D%92%E9%87%8E/</guid><description>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8de823138bee.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;之所以接触到这本书，是因为在电子书软件上看到奥巴马推荐书籍，其中这一本书感觉很特别，而且评分还不错，所以就决定看一看。刚开始看了下介绍，说是一个徒步旅行爱好者的自传，估计书内也就写写旅途的风景、风餐露宿的艰辛这样子，应该不会很“精彩”，结果它的写作很有自己的独到之处，完全不会感觉到无聊，看一小章节的内容根本停不下来，甚至我到最后，看到书页只剩10%的时候，有一种我快与这本书告别了，很舍不得的感觉，这种如获至宝的心理一直伴随我的阅读。
之前本身是纸质书籍的拥趸，比较喜欢那种纸质书籍的沉淀感和完成阅读的成就感。后来慢慢接触和接受电子书籍后，发现电子书有一个纸质书没有的优势：link。我找到这本书是因为我在《太空漫游》中提到了一本书（好像是），我link到那书中看到了“奥巴马推荐”，又所有“奥巴马推荐”中找了基本比较感兴趣的，其中就有《走出荒野》，《走出荒野》的女主也很喜欢看书，里面提到了一些书我又大概收藏5、6本。所以我的原本贫瘠的书单就这么一路link发展壮大。这些书远比“TOP书籍榜单“、”国内外必读经典”这类书好太多了。看完一本纸质书很容易产生不知道再看啥的境地，电子书就不会有这种情况。&lt;/p&gt;</description><content:encoded>&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8de823138bee.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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;之所以接触到这本书，是因为在电子书软件上看到奥巴马推荐书籍，其中这一本书感觉很特别，而且评分还不错，所以就决定看一看。刚开始看了下介绍，说是一个徒步旅行爱好者的自传，估计书内也就写写旅途的风景、风餐露宿的艰辛这样子，应该不会很“精彩”，结果它的写作很有自己的独到之处，完全不会感觉到无聊，看一小章节的内容根本停不下来，甚至我到最后，看到书页只剩10%的时候，有一种我快与这本书告别了，很舍不得的感觉，这种如获至宝的心理一直伴随我的阅读。
之前本身是纸质书籍的拥趸，比较喜欢那种纸质书籍的沉淀感和完成阅读的成就感。后来慢慢接触和接受电子书籍后，发现电子书有一个纸质书没有的优势：link。我找到这本书是因为我在《太空漫游》中提到了一本书（好像是），我link到那书中看到了“奥巴马推荐”，又所有“奥巴马推荐”中找了基本比较感兴趣的，其中就有《走出荒野》，《走出荒野》的女主也很喜欢看书，里面提到了一些书我又大概收藏5、6本。所以我的原本贫瘠的书单就这么一路link发展壮大。这些书远比“TOP书籍榜单“、”国内外必读经典”这类书好太多了。看完一本纸质书很容易产生不知道再看啥的境地，电子书就不会有这种情况。&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%a5%b3%e7%8e%8b%e7%9a%84%e6%97%85%e8%a1%8c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;作者在失去至亲、家庭分裂、巨额大学债务、沉迷drug之后，也许是想对重新认识自己，做足了“万全”准备来到太平洋屋脊步道。对于一个从来没有徒步经验的人来说，太平洋屋脊步道是最高难度的。她把她装了过多东西的背包称为“怪兽”，由于过于沉重甚至不能正常的背起“怪兽”，这个户外新手也就这要出发了。完成这个整个步道需要走4-6个月的时间，途中还需要事先计划补给点，把食物和一些必需品按计划事先寄送到那些地方，到达补给点补给完后再踏上步道继续前进。旅途中的痛苦虽然很难感受，但是能感受到有多痛苦，作者光是脚趾甲就拔掉了6个。这种痛苦和一些意外情况一般人无法忍受，所以人们挑战这条步道的“失败率”也是很高的，你需要一个异常强健的体格、完备的计划和一些运气。
即使野外有野兽、毒蛇、暴晒、冰川、缺水、受伤等等危险，但是都比不上“人”更危险。特别是对于一个20多岁的独自旅行的姑娘。当体验到“人”所带来的潜在危险后，这些大自然的客观危险甚至会感觉到轻松。这让我想起前不久看的美剧《最后的生还者》的情节，在世界末日的背景下，遇到僵尸不是最可怕的，最可怕的是遇到人类。
作者似乎有些好色（至少对性保守的人来说是这样），也可能老美都是这样的开放态度。在踏上步道前会跟很多男人来个一夜情，她很享受这种感觉，毫不避讳的描写这种生理上的需求和捕获男子的胜利感。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;我渴望的，不是一个可以爱的人，而只是一个可以紧贴我的身体的人&lt;/p&gt;
&lt;/blockquote&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="#%e5%a4%aa%e5%b9%b3%e6%b4%8b%e5%b1%8b%e8%84%8a%e6%ad%a5%e9%81%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/5e5f1fbbc068.png" alt="https://i0.wp.com/atlasguides.com/wp-content/uploads/2018/05/PCT_Map_mobile.png" /&gt;
太平洋屋脊步道（Pacific Crest Trail）是世界著名步道，步道位于美国西部的山脉中，这个山脉被戏称美国龙脉···步道信息非常好找，信息十分健全，作者也是根据步道指南来做准备工作和意外情况的处理。步道全长4k公里，从美加边境到美墨边境横跨美国本土，经过华盛顿州、俄勒冈州、加州，也是&lt;a href="https://www.pcta.org/our-work/national-trails-system/" target="_blank" rel="noreferrer"&gt;美国国家景观步道&lt;/a&gt;之一。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2bc7e1e56723.png" alt="https://www.pcta.org/wp-content/uploads/2019/04/National-Trails-50th-Map-02-09-18.jpg?x48626" /&gt;
我基本没有接触过徒步，对徒步的概念还是零，所以只有当个键盘侠羡慕一下背包客们。稍微搜索了一下户外徒步，有很多东西需要学习，户外徒步不仅能看到绝佳的风景，甚至还有心理治疗的功能，轻松的就搜索到徒步心理治疗协会。引用一下原著在步道上时的一点精神世界的描写：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;现在的我，整置身于这世界中，用一种全新的方式活着。如此居无定所地活着，头上连一方遮风避雨的屋顶也没有，让这个世界既扩大了许多，也缩小了不少。&lt;/p&gt;
&lt;/blockquote&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%82%b9%e9%87%91%e4%b9%8b%e7%ac%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在阅读本书时，我总是会想到《Educated:a memoir》，她们都是以回忆录的方式描述一段过往，她俩不仅写作手法有相似之处，连成长经历也很像——在与世隔绝的山里长大、有个家暴的父亲、一个落后的家庭生活、自身意外的超级能读书而考上好大学。
更重要的是她们的写作手法很容易抓住读者的情绪，不会让读者产生无聊沉闷的感觉。我没有很好的总结她们是怎么写作的，有一点我有特别留意——情绪的积累和意外之举。
举个例子，在作者把她母亲的骨灰撒进泥土时，她留了几块大些的骨骼，迟迟不肯撒手，最后把这几块未燃尽的骨头放进嘴里吞了下去。
我看到这里惊呆了，她在书中很多地方都有描写她跟她母亲的感情，母亲的离世对她影响非常大，在平淡地（或者说绝望地）描述完母亲死亡和火化之后，由于不想对母亲撒手，她选择把她母亲的骨头吞到肚子里，这样就能跟母亲融为一体了！这是怎样的一种情绪，才能催生这种常人无法接受的动作来寄托这沉重的感情。这个吞咽动作比不断的重复思念的感情要来的强烈的多，也更能抓住观众的眼球。
还有一段关于安全套的情节。一个老背包客在看到她背的东西过多后，帮助她整理背包，把一些根本用不到的东西都扔掉，老背包客找到了一大包TT，“你确定需要这些东西吗？”她有过一段步道经历后就知道这玩意儿完全没用，不过在扔掉这一大包TT时偷偷留了一个~然后
在第二天睡醒后这个TT不见了···
这些情节太剧情化我甚至有点怀疑是编的，不过我仔细看了作者序，她说只是忽略了某些情节，并保证事件都是真实的。
不管怎样，一点点超出现实逻辑的情节在写作中非常必要，能够抓住读者的心。这些点金之笔本身的真实性并不重要，重要的是得有这一笔。举一个我比较喜欢的电影《杀人回忆》的一段情节，相信很多人都看过。老警察在多年后回到案发现场，见到一个小孩，那个小孩说刚才也有一个人也像你一样蹲在这里看这个下水道，老警察立即意识到这个人可能是凶手，他问小孩那个人长什么样，小孩说：“普通人的样子”。这一段就是神来之笔，这部电影很多人很纠结凶手到底是谁，其实是谁并不重要，“凶手是普通人”这才是这个电影作品想表达的含义。&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%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本身无聊的剧情却写出了吸引眼球的著作，内容本身也很有深度，感情充沛真实，是一篇跟随作者一起回归自然、探索自我的回忆录，非常值得阅读！
近期好的书籍源源不断，书架已经拉的比较满了，不过我一点也不担心吃灰，因为我相信这些书的质量跟这部作品一样，达到爱不释手的地步，无需自我鞭策便可以沉浸式地阅读。引用一下一个徒步大佬博客的内容&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&amp;gt; 你最喜欢的一段景色是哪一段？
&amp;gt; 下一段&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title>分区权限问题导致执行计划不正确</title><link>https://lastdba.com/2024/08/12/%E5%88%86%E5%8C%BA%E6%9D%83%E9%99%90%E9%97%AE%E9%A2%98%E5%AF%BC%E8%87%B4%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E4%B8%8D%E6%AD%A3%E7%A1%AE/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E5%88%86%E5%8C%BA%E6%9D%83%E9%99%90%E9%97%AE%E9%A2%98%E5%AF%BC%E8%87%B4%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E4%B8%8D%E6%AD%A3%E7%A1%AE/</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;业务昨晚对sql进行了更新，之前没有DATE_CREATED字段（是分区键），跑的很快。发版后加了分区字段，本身是为了减少分区数量的访问，但是加了以后UPDATE执行却变慢了。
before：&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;业务昨晚对sql进行了更新，之前没有DATE_CREATED字段（是分区键），跑的很快。发版后加了分区字段，本身是为了减少分区数量的访问，但是加了以后UPDATE执行却变慢了。
before：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;update&lt;/span&gt; TABLE_RECORD
&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; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LOCALTIMESTAMP&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;WHERE&lt;/span&gt; APPL_NO &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;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;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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;after：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;update&lt;/span&gt; TABLE_RECORD
&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; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LOCALTIMESTAMP&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;WHERE&lt;/span&gt; APPL_NO &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;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;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&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 style="color:#66d9ef"&gt;AND&lt;/span&gt; DATE_CREATED &lt;span style="color:#f92672"&gt;&amp;gt;&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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; now()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;发版前访问时间是毫秒级，发版后访问时间是10s，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="#%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="#%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e7%9c%8b%e4%b8%8a%e5%8e%bb%e6%98%af%e6%ad%a3%e7%a1%ae%e7%9a%84" 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;&lt;span style="color:#f92672"&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; TABLE_RECORD
&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.TABLE_RECORD&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_TABLE_RECORD &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;32&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; nextval(&lt;span style="color:#e6db74"&gt;&amp;#39;seq_TABLE_RECORD&amp;#39;&lt;/span&gt;::regclass) &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; appl_no &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;100&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; r_appl_no &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;100&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;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; created_by &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;100&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:#e6db74"&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;::character varying &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; updated_by &lt;span style="color:#f92672"&gt;|&lt;/span&gt; character varying(&lt;span style="color:#ae81ff"&gt;100&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:#e6db74"&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;::character varying &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_updated &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;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;date_TABLE_RECORD&amp;#34;&lt;/span&gt; btree (date_created)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_dateupdated&amp;#34;&lt;/span&gt; btree (date_updated)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idx_applnodeleted&amp;#34;&lt;/span&gt; btree (appl_no, is_deleted)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;nk_TABLE_RECORD&amp;#34;&lt;/span&gt; btree (appl_no)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: TABLE_RECORD_202211 &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;2022-11-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;2022-12-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; TABLE_RECORD_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; TABLE_RECORD_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; TABLE_RECORD_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; TABLE_RECORD_202306 &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-06-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-07-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; TABLE_RECORD_202512 &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;2025-12-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;2026-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; TABLE_RECORD_other &lt;span style="color:#66d9ef"&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;这个sql会访问近2个月的分区，这2个分区都是有数据的，上面的update只会更新一条数据。
刚开始分析问题非常困惑，因为我们explain的时候，执行计划是没有问题的
explain分区扫描信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202302_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202302 TABLE_RECORD_4 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;485&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202303_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202303 TABLE_RECORD_5 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;482&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202304_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202304 TABLE_RECORD_6 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;481&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_applnodeleted_25 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202305 TABLE_RECORD_7 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&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;483&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_14 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202306 TABLE_RECORD_8 (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;56&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;45&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;18&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;485&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_38 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202307 TABLE_RECORD_9 (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3502&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202308 TABLE_RECORD_10 (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3502&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;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;),tableoid::regclass &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; TABLE_RECORD &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&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;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tableoid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;56558&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202303
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4436&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202211
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;6929&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202306
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;945&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202305
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1413&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202304
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;5499&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202212
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1486&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;4722&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202302&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;执行计划看上去对不同的分区访问了不同的索引
date_TABLE_RECORD：分区键上的索引
idx_applnodeleted：appl_no, is_deleted组合索引
实际上sql可以通过DATE_CREATED近31天数据字段裁剪分区。但是如果在用这个字段的索引，那就没有任何过滤性了。而appl_no, is_deleted在分区中过滤性较好，真正的执行计划应该选择 idx_applnodeleted组合索引。
上面的explain执行计划虽然不是真正的执行计划，但是能看到5、6月份的走的索引是没有问题的，走的是appl_no, is_deleted组合索引。
查看真实的执行计划会执行sql，所以把update改成select，查看真实的执行计划&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;analyze&lt;/span&gt;,buffers,timing,&lt;span style="color:#66d9ef"&gt;verbose&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; TABLE_RECORD &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; APPL_NO &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&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; 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:#66d9ef"&gt;AND&lt;/span&gt; DATE_CREATED &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;&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;266&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;09&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;266&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;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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;565&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;566&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:#66d9ef"&gt;Output&lt;/span&gt;: &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; Buffers: shared hit&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; 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;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;265&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;95&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;56&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;388&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;558&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; Buffers: shared hit&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; Subplans Removed: &lt;span style="color:#ae81ff"&gt;37&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; idx_applnodeleted_25 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.TABLE_RECORD_202305 TABLE_RECORD_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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;) (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;059&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;059&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;0&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (((TABLE_RECORD_1.appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((TABLE_RECORD_1.is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((TABLE_RECORD_1.date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (TABLE_RECORD_1.date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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:#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_applnodeleted_14 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.TABLE_RECORD_202306 TABLE_RECORD_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;56&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;42&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;17&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;328&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;498&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (((TABLE_RECORD_2.appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((TABLE_RECORD_2.is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((TABLE_RECORD_2.date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (TABLE_RECORD_2.date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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;Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5867&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;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;195&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;654&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;18&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;select只访问了5月和6月两个分区，说明分区裁剪没问题；两个分区都是idx_applnodeleted索引，所以索引选择也没问题。
直接执行select语句，执行时间是ms级。&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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:#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; TABLE_RECORD &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; APPL_NO &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&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; 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:#66d9ef"&gt;AND&lt;/span&gt; DATE_CREATED &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:#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;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;Time: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;946&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;分析到这里，看上去执行计划正常，执行时间正常&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="#%e4%b8%9a%e5%8a%a1sql%e4%bb%8d%e7%84%b6%e7%bc%93%e6%85%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;但是，postgresql日志中仍然能抓到慢sql，update执行了10s&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2023&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;06&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;11&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;06&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;077&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldbopr&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;116286&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.78.90:51871&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;649&lt;/span&gt;cdebf.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;c63e,&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE&amp;#34;&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;06&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;09&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;39&lt;/span&gt; CST,&lt;span style="color:#ae81ff"&gt;759&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12440291&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4002354803&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;duration: 10287.105 ms &amp;#34;&lt;/span&gt; plan:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query Text: &lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; TABLE_RECORD
&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; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LOCALTIMESTAMP&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;WHERE&lt;/span&gt; APPL_NO &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;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;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&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 style="color:#66d9ef"&gt;AND&lt;/span&gt; DATE_CREATED &lt;span style="color:#f92672"&gt;&amp;gt;&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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; now()
&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;on&lt;/span&gt; TABLE_RECORD (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;203&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;79&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;39&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2960&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;on&lt;/span&gt; TABLE_RECORD_202211 TABLE_RECORD_1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202304_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202304 TABLE_RECORD_6 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;481&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202305_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202305 TABLE_RECORD_7 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;483&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202306_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202306 TABLE_RECORD_8 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;485&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_applnodeleted_38 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202307 TABLE_RECORD_9 (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3502&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&lt;/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;5、6月分区还是用的date_created分区键上的索引，执行计划只估算了1行，实际上这2个分区实际上都有百万行数据。
分析到这里就非常困惑，优化器本身可以走到更好的索引，explain也看到走到了那个索引，但是业务sql就是没有走正确的索引。&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%e7%bb%9f%e8%ae%a1%e4%bf%a1%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为是pgsql执行计划的问题，首先都会想到收集统计信息
问题发生后，收集了分区表父表和子表的统计信息，并且担心会话缓存了执行计划（plan_cache_mode=auto），将统计信息收集时间之前的会话全部kill。
日志仍然显示sql执行10s，说明不是统计信息的问题。
做到这里问题仍然没有解决，似乎已经黔驴技穷了。&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%e6%a0%b9%e5%9b%a0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;前面分析执行计划的时候，dba explain的执行计划与应用的执行计划不一致，不过我们都是用postgres超级用户执行的。切换为应用用户再次explain执行，执行计划结果与日志中的执行计划一致！
因为之前出现过原生分区表权限问题，导致执行计划异常的情况。所以立即检查分区表分区的权限
父表权限&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;dp&lt;span style="color:#f92672"&gt;+&lt;/span&gt; TABLE_RECORD
&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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD &lt;span style="color:#f92672"&gt;|&lt;/span&gt; partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldbdata&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arwdDxt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r_lzldbdata_qry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r_lzldbdata_dml&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arwd&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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;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;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;dp&lt;span style="color:#f92672"&gt;+&lt;/span&gt; TABLE_RECORD_202505
&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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; TABLE_RECORD_202505 &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; lzldbdata&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arwdDxt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;分区权限少了r_lzldbdata_dml这个角色的,这个角色是授权给业务用户的。
立即执行授权，问题解决&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;update&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202305 &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; r_lzldbdata_dml;
&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;select&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;insert&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202306 &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; r_lzldbdata_dml;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;再次用opr用户explain，执行计划正确，5、6月走了正常的索引
&lt;code&gt;\c - lzldbopr&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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202303_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202303 TABLE_RECORD_5 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;482&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; TABLE_RECORD_202304_date_created_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202304 TABLE_RECORD_6 (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;44&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;481&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: ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; now()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; idx_applnodeleted_25 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202305 TABLE_RECORD_7 (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;43&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;39&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;483&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_14 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202306 TABLE_RECORD_8 (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;56&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;57&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;17&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;485&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_38 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202307 TABLE_RECORD_9 (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3502&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; idx_applnodeleted_1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; TABLE_RECORD_202308 TABLE_RECORD_10 (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3502&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: (((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;LZLMATH20230132302302&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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日志上也未再观察到慢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%e6%b2%a1%e5%a4%8d%e7%8e%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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:#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; lzldbdata
&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; &lt;span style="color:#66d9ef"&gt;PUBLIC&lt;/span&gt;.LZLPARTITION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; APPL_NO varchar(&lt;span style="color:#ae81ff"&gt;100&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;	IS_DELETED varchar(&lt;span style="color:#ae81ff"&gt;8&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; DATE_UPDATED &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;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;--indexes
&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; DATE_LZLPARTITION &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PUBLIC&lt;/span&gt;.LZLPARTITION (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; NK_LZLPARTITION &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PUBLIC&lt;/span&gt;.LZLPARTITION (APPL_NO);
&lt;/span&gt;&lt;/span&gt;&lt;span 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;--privs
&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;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.LZLPARTITION &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; r_lzldbdata_qry;
&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;SELECT&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;DELETE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.LZLPARTITION &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; r_lzldbdata_dml;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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
&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; LZLPARTITION_202301 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION_202302 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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 style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION_202303 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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; LZLPARTITION_202304 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION_202305 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; LZLPARTITION_202306 partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; LZLPARTITION &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-06-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-07-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;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;insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;.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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &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:#e6db74"&gt;&amp;#39;N&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to_char(to_date(&lt;span style="color:#e6db74"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;YYYY-MM-DD&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; n &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; minute&amp;#39;&lt;/span&gt;) ::interval, &lt;span style="color:#e6db74"&gt;&amp;#39;YYYY-MM-DD&amp;#39;&lt;/span&gt;)::&lt;span style="color:#e6db74"&gt;&amp;#34;date&amp;#34;&lt;/span&gt;,
&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:#66d9ef"&gt;from&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; generate_series(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;300000&lt;/span&gt;) n&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; &lt;span style="color:#66d9ef"&gt;count&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;),tableoid::regclass &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlpartition &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&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;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; tableoid 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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;44640&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202301
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;40320&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202302
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;44640&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202303
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;43200&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202304
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;44640&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202305
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;43200&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202306
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;39361&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202307&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;##&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; lzlpartition
&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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition &lt;span style="color:#f92672"&gt;|&lt;/span&gt; partitioned &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzldbdata&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arwdDxt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r_lzldbdata_qry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;r&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; r_lzldbdata_dml&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arwd&lt;span style="color:#f92672"&gt;/&lt;/span&gt;lzldbdata &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;
&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;dp&lt;span style="color:#f92672"&gt;+&lt;/span&gt; lzlpartition_202306
&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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlpartition_202306 &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;/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;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; lzlpartition &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; APPL_NO &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;217450&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; IS_DELETED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;N&amp;#39;&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; 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:#66d9ef"&gt;AND&lt;/span&gt; DATE_CREATED &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; &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;36&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;76&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;77&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;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;74&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;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Subplans Removed: &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; &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; lzlpartition_202305_appl_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition_202305 lzlpartition_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;15&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;19&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;217450&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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; lzlpartition_202306_appl_no_idx &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlpartition_202306 lzlpartition_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;15&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;19&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((appl_no)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;217450&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((is_deleted)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; now()) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; (date_created &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; (now() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;31 days&amp;#39;&lt;/span&gt;::interval &lt;span style="color:#66d9ef"&gt;day&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版本也是这样的，看上去是一个通用行为。
但是就算这样也没有复现出来，测试结果走了正确的索引，没有像生产环境那样走错误的索引。&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%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;因为我们收集了统计信息并kill了会话，不应该是缓存执行计划的问题。执行了grant后，分区执行计划立即正确（甚至grant一个分区，对一个分区），所以比较确认是分区权限导致分区执行计划异常的。分析和处理问题的过程总结如下&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;切换应用用户查看执行计划。直接用超级用户登陆查看执行计划是通用做法，但是查看到的执行计划还是不对的。&lt;/li&gt;
&lt;li&gt;分区表子表的权限问题。根因是postgresql分区表子表上的权限与父表不一致，导致执行计划异常，也就是说权限问题影响了pg的执行计划。&lt;/li&gt;
&lt;li&gt;该问题不好复现，非常非常偶发。&lt;/li&gt;
&lt;li&gt;权限导致执行计划异常这个问题非常隐蔽，不好定位。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;想深入讨论2个问题&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;权限问题不应该影响执行计划。为什么权限会影响执行计划？&lt;/li&gt;
&lt;li&gt;子表权限与父表不一致。为什么子表没有全部继承父表权限？
已提交BUG看看官方咋说&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>花式分析一个5M的SQL占用70GB内存</title><link>https://lastdba.com/2024/08/12/%E8%8A%B1%E5%BC%8F%E5%88%86%E6%9E%90%E4%B8%80%E4%B8%AA5m%E7%9A%84sql%E5%8D%A0%E7%94%A870gb%E5%86%85%E5%AD%98/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%8A%B1%E5%BC%8F%E5%88%86%E6%9E%90%E4%B8%80%E4%B8%AA5m%E7%9A%84sql%E5%8D%A0%E7%94%A870gb%E5%86%85%E5%AD%98/</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="#%e8%bf%9b%e7%a8%8b%e5%86%85%e5%ad%98%e5%88%86%e6%9e%90" 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:#e6db74"&gt;&amp;#34;WAL writer process (PID 66902) was terminated by signal 6: Aborted&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&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;从日志中找到被kill的postmaster进程66902&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="#%e8%bf%9b%e7%a8%8b%e5%86%85%e5%ad%98%e5%88%86%e6%9e%90" 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:#e6db74"&gt;&amp;#34;WAL writer process (PID 66902) was terminated by signal 6: Aborted&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;postmaster&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;从日志中找到被kill的postmaster进程66902&lt;/p&gt;
&lt;p&gt;到osw中找进程消耗的内存。由于top没有PPID，PS没有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;USER PID PPID PRI %CPU %MEM VSZ RSS WCHAN S STARTED TIME COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66478&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 8.7 10.6 &lt;span style="color:#ae81ff"&gt;57488380&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56389972&lt;/span&gt; - R 17:13:03 00:02:47 postgres: BIND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;211277&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66478&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 7.8 9.6 &lt;span style="color:#ae81ff"&gt;52294700&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;51127480&lt;/span&gt; - R 17:13:03 00:02:31 postgres: BIND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;222749&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66478&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 22.7 9.3 &lt;span style="color:#ae81ff"&gt;51320000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;49073368&lt;/span&gt; - R 17:35:33 00:02:09 postgres: BIND
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgres &lt;span style="color:#ae81ff"&gt;39513&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;66478&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 2.9 6.8 &lt;span style="color:#ae81ff"&gt;38651084&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36354736&lt;/span&gt; ep_poll S 16:13:03 00:02:43 postgres: idle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过PPID找个backend消耗较高的进程，比如211276进程进行进一步分析&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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@lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ zcat /osw/oswtop/toposw.dat.gz |grep &lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&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;211276&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;3271756&lt;/span&gt; 1.1g 1.1g S 7.3 0.2 0:03.93 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&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;3291784&lt;/span&gt; 1.3g 1.2g R 96.4 0.2 0:11.87 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&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;7369628&lt;/span&gt; 6.0g 2.1g R 100.0 1.2 0:46.58 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 17.0g 15.9g 2.1g R 100.0 3.2 1:16.70 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 28.8g 27.7g 2.1g R 100.0 5.5 1:46.82 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 41.4g 40.4g 2.1g R 100.0 8.0 2:16.99 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 54.7g 53.7g 2.1g R 88.8 10.7 2:47.60 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 66.5g 64.9g 2.1g R 34.7 12.9 3:22.76 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 71.0g 68.2g 2.1g R 99.1 13.6 3:52.94 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&lt;/span&gt; postgres &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 74.9g 71.2g 2.1g R 100.0 14.2 4:23.05 postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;211276&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;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; R 100.0 0.0 4:45.65 postgres&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;top可以通过RES-SHR=USS来判断进程私有内存的消耗。211276进程的内存几分钟内暴涨到70g挂掉，并且都是进程私有内存消耗&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="#sql%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;PG日志中一个5M的SQL，包含5000+个union all，3万个变量
执行计划长达7W行&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Append (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;218196&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;218216&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;1318&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1628&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; &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; table1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table1nfo (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;5&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;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;Index&lt;/span&gt; Cond: ((col1)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((colcolcol)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InitPlan &lt;span style="color:#ae81ff"&gt;2&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;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;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; table1 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table1nfo table1nfo_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;29&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&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;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;Index&lt;/span&gt; Cond: ((col1)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((colcolcol)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxx&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; InitPlan &lt;span style="color:#ae81ff"&gt;10544&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;10543&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;Aggregate&lt;/span&gt; (cost&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;58&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;59&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;32&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; table2 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table2col t_1317 (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;56&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;58&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;19&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: ((ididid)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: ((idididid)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&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;执行计划结构非常简单，1w个子计划查数据，最后append结果。&lt;/p&gt;
&lt;p&gt;就是这么个拼接怪SQL把backend进程打到70GB。其实不用深入分析也知道，这个sql是有问题的，把union all减少，问题应该是可以修复的（事实上就是这样）。但是如果仔细想想，这里有很多问题可以深入分析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;为什么5M的SQL可以把内存打到70GB？&lt;/li&gt;
&lt;li&gt;数据本身跟内存有关系吗？是因为返回数据过多导致的吗？&lt;/li&gt;
&lt;li&gt;是解析数据缓存大，还是因为执行计划缓存数据大？&lt;/li&gt;
&lt;li&gt;work_mem明明不大，为什么没有起到限制operation内存的效果？&lt;/li&gt;
&lt;/ol&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%9d%e6%ad%a5%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果一个5M的sql缓存在backend中，里面至少应该包含所要的元数据、SQL解析数据、执行计划缓存信息
我们之前碰到过几十万个表/分区表的元数据缓存导致relcache过大，从而导致backend内存很大。而这个库的表不多，初步可以排除relcache问题（后续查看dump内存可以确认排除）。
SQL解析数据理应不会太多，5M的sql解析出来至少不应该是70G。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;work_mem的内存限制and more：&lt;/strong&gt;
work_mem只限制每个operation的sort（可以用到sort的操作）、hash（可以用到hash的操作）的内存。这里就存在multiple sort/hash的问题，一个sql有多个sort的话可使用多个work_mem，所以pg13新增&lt;code&gt;hash_mem_multiplier&lt;/code&gt;以限制一个语句中的hash使用次数。但是sort呢？sort目前没有multiplier参数，但是现实场景中问题较少，因为一个语句中大量的plan node存在sort操作的情况是比较少的，想想代价就很高，优化器源码中也有把排序操作放在执行计划最后的逻辑，以减少反复排序。&lt;/p&gt;
&lt;p&gt;这里实例的work_mem为128M，并且这个库是pg13+的，hash_mem_multiplier为1，基本可以排除执行计划使用大量hash操作导致内存暴涨的问题。另外从上面的执行计划看，完全没有sort和hash操作，所以可以排除sort/hash操作过多导致的问题。&lt;/p&gt;
&lt;p&gt;所以之前的提问，&lt;em&gt;“work_mem明明不大，为什么没有起到限制operation内存的效果？”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;因为sql语句只有union all，没有任何排序和hash操作，所以work_mem不会限制这里的内存&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;其他plan node&lt;/strong&gt;:
无论怎样，work_mem只（？）限制sort/hash。plan operation有这么多类型的操作，是不是没有限制？&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%e7%8e%b0%e9%97%ae%e9%a2%98%e5%b9%b6%e6%b7%b1%e5%85%a5%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&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%a9%ba%e8%a1%a8%e5%a4%8d%e7%8e%b0%e5%86%85%e5%ad%98%e9%a3%99%e5%8d%87" 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 style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzl1(col1 varchar(&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;--非常多union all的查询
&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; lzl1 &lt;span style="color:#66d9ef"&gt;union&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;all&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; lzl1 &lt;span style="color:#66d9ef"&gt;union&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...(&lt;span style="color:#ae81ff"&gt;5000&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;个&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;union&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;sql大小150KB)
&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; lzl1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（UNION ALL过多可能超过max_stack_depth限制）
一个空表，多个union all，直接就容复现出来内存飙升问题。不仅如此，还可以发现sql运行完后，backend的内存回收了。&lt;/p&gt;
&lt;p&gt;因为是一个空表，数据文件0kb，所以可以排除数据问题导致内存飙高。所以“数据本身跟内存有关系吗？是因为返回数据过多导致的吗？”——跟数据本身关系不大。&lt;/p&gt;

&lt;h4 class="relative group"&gt;strace操作系统调用分析
 &lt;div id="strace操作系统调用分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#strace%e6%93%8d%e4%bd%9c%e7%b3%bb%e7%bb%9f%e8%b0%83%e7%94%a8%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;执行语句的同时通过strace -p抓操作系统调用信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; strace -p &lt;span style="color:#ae81ff"&gt;198337&lt;/span&gt; &amp;gt; strace.198337 2&amp;gt;&amp;amp;&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;在看strace信息前先了解一点点linux调用函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/epoll_wait.2.html" target="_blank" rel="noreferrer"&gt;epoll_wait&lt;/a&gt;:等待event，什么都不做的进程就是这个状态&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man3/recvfrom.3p.html" target="_blank" rel="noreferrer"&gt;recvfrom&lt;/a&gt;:receive a message from a socket，从socket接收消息&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man3/recvfrom.3p.html" target="_blank" rel="noreferrer"&gt;getrusage&lt;/a&gt;:get resource usage，获取资源使用情况&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/brk.2.html" target="_blank" rel="noreferrer"&gt;brk&lt;/a&gt;: program break.Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.操作系统底层管理内存的函数，malloc本质上也是在调用brk。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/lseek.2.html" target="_blank" rel="noreferrer"&gt;lseek&lt;/a&gt;:repositions the file offset of the open file description associated with the file descriptor fd to the argument offset，定位文件偏移量用的&lt;/li&gt;
&lt;li&gt;&lt;a href="" &gt;write&lt;/a&gt;:write to a file descriptor，write不保证写入磁盘&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man3/sendto.3p.html" target="_blank" rel="noreferrer"&gt;sendto&lt;/a&gt;:send a message on a socket，从socket发送消息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中，lseek、write、sendto等系统函数中包含fd文件描述符信息&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在/proc/[pid]/pd目录中缓存了进程持有的文件描述符，从文件描述符反查relation，可以找到SQL执行打开的表lzl1&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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@lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cd /proc/198337/fd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwx------ &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; Jan &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; 22:59 &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; -&amp;gt; /pgdata/lzl/data13/base/16385/16386
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ oid2name -d lzldb -f &lt;span style="color:#ae81ff"&gt;16386&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;From database &lt;span style="color:#e6db74"&gt;&amp;#34;lzldb&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filenode Table 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 style="color:#ae81ff"&gt;16386&lt;/span&gt; lzl1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;strace信息非常多，但是结构简单：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;strace: Process &lt;span style="color:#ae81ff"&gt;198337&lt;/span&gt; attached
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epoll_wait&lt;span style="color:#f92672"&gt;(&lt;/span&gt;4, &lt;span style="color:#f92672"&gt;[{&lt;/span&gt;EPOLLIN, &lt;span style="color:#f92672"&gt;{&lt;/span&gt;u32&lt;span style="color:#f92672"&gt;=&lt;/span&gt;44314568, u64&lt;span style="color:#f92672"&gt;=&lt;/span&gt;44314568&lt;span style="color:#f92672"&gt;}}]&lt;/span&gt;, 1, -1&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;&lt;span style="color:#75715e"&gt;## step1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34;Q\0\2p\372select col1 from lzl1 union&amp;#34;&lt;/span&gt;..., 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34; all\nselect col1 from lzl1 union&amp;#34;&lt;/span&gt;..., 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34; all\nselect col1 from lzl1 union&amp;#34;&lt;/span&gt;..., 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34; all\nselect col1 from lzl1 union&amp;#34;&lt;/span&gt;..., 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34; all\nselect col1 from lzl1 union&amp;#34;&lt;/span&gt;..., 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4347&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## step2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x34d5000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x3cd5000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x3cd5000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x3cd5000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x88cd6000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x894d6000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x894d6000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## step3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## step4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x89cd6000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8a4d6000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a4d6000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a4d6000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a516000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8a556000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a556000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## step5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;write&lt;span style="color:#f92672"&gt;(&lt;/span&gt;2, &lt;span style="color:#e6db74"&gt;&amp;#34;2024-01-26 23:08:01.800 CST [198&amp;#34;&lt;/span&gt;..., 165521&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;165521&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a556000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8a57d000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a57d000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a57d000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8a59f000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a59f000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8d449000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8d46b000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8d46b000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8d46b000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8d48d000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8d48d000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#step6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lseek&lt;span style="color:#f92672"&gt;(&lt;/span&gt;37, 0, SEEK_END&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#step7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8dcb1000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8dcb1000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8c179000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8c179000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8c179000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8c179000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8c179000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x8a526000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x8a526000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;0x34d5000&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x34d5000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brk&lt;span style="color:#f92672"&gt;(&lt;/span&gt;NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0x34d5000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#step8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto&lt;span style="color:#f92672"&gt;(&lt;/span&gt;8, &lt;span style="color:#e6db74"&gt;&amp;#34;\2\0\0\0\230\0\0\0\1@\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&amp;#34;&lt;/span&gt;..., 152, 0, NULL, 0&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;152&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sendto&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, &lt;span style="color:#e6db74"&gt;&amp;#34;T\0\0\0\35\0\1col1\0\0\0\0\0\0\0\0\0\4\23\377\377\0\0\0\5\0\0C\0&amp;#34;&lt;/span&gt;..., 50, 0, NULL, 0&lt;span style="color:#f92672"&gt;)&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:#75715e"&gt;#step9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recvfrom&lt;span style="color:#f92672"&gt;(&lt;/span&gt;9, 0xddcf60, 8192, 0, NULL, NULL&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; -1 EAGAIN &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Resource temporarily unavailable&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epoll_wait&lt;span style="color:#f92672"&gt;(&lt;/span&gt;4, strace: Process &lt;span style="color:#ae81ff"&gt;198337&lt;/span&gt; detached
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;detached ...&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;从fd=9的socket接收到message，也就是我们发送的union all语句&lt;/li&gt;
&lt;li&gt;brk分配内存，进程的内存从0x34d5000（54MB）涨到0x894d6000（2.1GB）&lt;/li&gt;
&lt;li&gt;lseek表lzl1&lt;/li&gt;
&lt;li&gt;内存上涨4MB&lt;/li&gt;
&lt;li&gt;write到fd=2的文件，就是日志文件；内存上涨48MB&lt;/li&gt;
&lt;li&gt;lseek表lzl1&lt;/li&gt;
&lt;li&gt;内存到达峰值0x8dcb1000（2.1GB），开始通过brk释放内存，直到0x34d5000（54MB），跟开始时分毫不差&lt;/li&gt;
&lt;li&gt;从socket返回消息，也就是返回查询结果&lt;/li&gt;
&lt;li&gt;从fd=9的socket接收到空消息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;strace分析到的东西不多，不过可以看到操作系统为进程分配和释放内存的具体过程。&lt;/p&gt;

&lt;h4 class="relative group"&gt;dump内存分析
 &lt;div id="dump内存分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dump%e5%86%85%e5%ad%98%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;内存飙高后的pmap信息：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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@lzl pg_log&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pmap -x &lt;span style="color:#ae81ff"&gt;76207&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;76207: postgres: postgres lzldb &lt;span style="color:#f92672"&gt;[&lt;/span&gt;local&lt;span style="color:#f92672"&gt;]&lt;/span&gt; SELECT 
&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;7984&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2192&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;0000000000dcc000 &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;0000000000dcd000 &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; rw--- postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000000ddc000 &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&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;0000000001e49000 &lt;span style="color:#ae81ff"&gt;264&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;224&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;224&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;0000000001e8b000 &lt;span style="color:#ae81ff"&gt;1812380&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1804400&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1804400&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;...
&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;2089384&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1810232&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1807384&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这里没有展示具体段是什么，但是可以确认内存起始地址为1e49000的内存段占用最多。此时需要smap来看是什么段，smap的段信息更为准确：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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@lzl 76207&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ cat smaps |grep 1e49000 -A &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;01e49000-01e8b000 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;Size: &lt;span style="color:#ae81ff"&gt;264&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;01e8b000-70872000 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;Size: &lt;span style="color:#ae81ff"&gt;1812380&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;1804400&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;1804400&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;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;1804400&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;1804400&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;1804400&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;heap段，PSS进程私有内存达到1.8GB！
&lt;em&gt;（这里本来应该dump 01e8b000-70872000内存段，但是gdb dump memory会报错，不太明白具体原因，大佬可以指点一下，谢谢！）&lt;/em&gt;
这里粗糙一点用gcore dump内存，比较难看，什么东西都有，没有发现占用特别多的内容。不过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;postgres@lzl lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ gcore -o /pgdata/lzl/gcore.dump &lt;span style="color:#ae81ff"&gt;76207&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;postgres@lzl lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ strings gcore.dump.76207&amp;gt; text.dump.76207
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@lzl lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ll -h
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r----- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres 2.0G Jan &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; 17:29 gcore.dump.76207
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r----- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; postgres postgres 5.2M Jan &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; 17:30 text.dump.76207&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;申请了2G的虚拟内存，占用1.8G的物理内存，实际上只存储了5.2M的数据！
用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-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;postgres@lzl lzl&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ hexdump -C gcore.dump.76207 |head -10000 |grep &lt;span style="color:#e6db74"&gt;&amp;#34;00 00 00 00 00 00 00 00&amp;#34;&lt;/span&gt;|wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;3690&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;log_planner_stats等信息
 &lt;div id="log_planner_stats等信息" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#log_planner_stats%e7%ad%89%e4%bf%a1%e6%81%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;为了验证是否缓存执行计划的问题
把复现环境的相关log参数&lt;strong&gt;先后&lt;/strong&gt;打开以观察parse、planner、executor阶段的资源消耗&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; log_parser_stats &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; log_planner_stats &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; log_executor_stats &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;从日志上看parse阶段的消耗内存较少，而planner的内存消耗较多
log planner 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;2024-01-26 18:01:41.592 CST &lt;span style="color:#f92672"&gt;[&lt;/span&gt;208503&lt;span style="color:#f92672"&gt;]&lt;/span&gt; LOG: PLANNER STATISTICS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-01-26 18:01:41.592 CST &lt;span style="color:#f92672"&gt;[&lt;/span&gt;208503&lt;span style="color:#f92672"&gt;]&lt;/span&gt; DETAIL: ! system usage stats:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ! 0.048955 s user, 0.004996 s system, 0.054077 s elapsed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ! &lt;span style="color:#f92672"&gt;[&lt;/span&gt;11.208034 s user, 1.313838 s system total&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;2255352&lt;/span&gt; kB max resident size
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ! 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/352&lt;span style="color:#f92672"&gt;]&lt;/span&gt; filesystem blocks in/out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ! 0/1315 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/563859&lt;span style="color:#f92672"&gt;]&lt;/span&gt; page faults/reclaims, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; swaps
&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;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; signals rcvd, 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0/0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; messages rcvd/sent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ! 0/0 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1/16&lt;span style="color:#f92672"&gt;]&lt;/span&gt; voluntary/involuntary context switches&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2GB的max resident size大小跟进程观察的res差不多，所以上面的信息可以回答刚才的问题：“是解析数据缓存大，还是因为执行计划缓存数据大？”——planner阶段消耗的内存。&lt;/p&gt;

&lt;h4 class="relative group"&gt;查看TopMemoryContext
 &lt;div id="查看topmemorycontext" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8btopmemorycontext" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;pg通过memorycontext管理backend进程的私有内存，可通过gdb输出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;TopMemoryContext: &lt;span style="color:#ae81ff"&gt;101488&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;48464&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;53024&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pgstat TabStatusArray lookup hash table: &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;1408&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;6784&lt;/span&gt; used
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TopTransactionContext: &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;7720&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;472&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;2048&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;6144&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;6880&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;1312&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;1854981336&lt;/span&gt; total in &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;7911304&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1847070032&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;Grand total: &lt;span style="color:#ae81ff"&gt;1856104056&lt;/span&gt; bytes in &lt;span style="color:#ae81ff"&gt;431&lt;/span&gt; blocks; &lt;span style="color:#ae81ff"&gt;8226712&lt;/span&gt; free &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;179&lt;/span&gt; chunks&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1847877344&lt;/span&gt; used&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;内存消耗最多的是MessageContext 1.8G
src/backend/utils/mmgr/README对MessageContext 的解释：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;MessageContext &amp;mdash; this context holds the current command message from the frontend, as well as any derived storage that need only live as long as the current message (for example, in simple-Query mode the parse and plan trees can live here). This context will be reset, and any children deleted, at the top of each cycle of the outer loop of PostgresMain. This is kept separate from per-transaction and per-portal contexts because a query string might need to live either a longer or shorter time than any single transaction or portal.&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;When creating a prepared statement, the parse and plan trees will be built in a temporary context that&amp;rsquo;s a child of MessageContext&lt;/p&gt;
&lt;/blockquote&gt;&lt;ul&gt;
&lt;li&gt;MessageContext缓存frontend发来传递的消息，包含派生的parse、plan tree信息&lt;/li&gt;
&lt;li&gt;parse and plan trees 是MessageContext的child，也就是说MessageContext回收，parse and plan trees 就回收&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里就的messagecontext还可以解释私有内存回收问题，planner阶段产生的plan tree内存数据是MessageContext的child，数据结果返回后MessageContext被回收，child内容也被回收，同样也可以解释从strace中观察的内存释放后跟释放前的大小是完全一致的。&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;回答最后一个问题：&lt;em&gt;“为什么5M的SQL可以把内存打到70GB？”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;绝大部分内存是在生产执行计划期间消耗的，planner申请了大量的内存，并且work_mem，hash_mem_multiplier只能限制到排序操作和hash操作，对于planner过程中的其他内存操作还无法限制，planner本身产生的plan tree并不大，但是申请内存时存在大量的内存空洞，导致本身M级的数据（元数据、parse tree、plan tree等等）存储在G级的内存中。&lt;/p&gt;
&lt;p&gt;这些SQL、parse tree、plan tree都缓存在MessageContext及其child中，消息发送完毕后，此部分产生的内存全部回收。&lt;/p&gt;</content:encoded></item><item><title>较少的分区也报错too many range table entries</title><link>https://lastdba.com/2024/08/12/%E8%BE%83%E5%B0%91%E7%9A%84%E5%88%86%E5%8C%BA%E4%B9%9F%E6%8A%A5%E9%94%99too-many-range-table-entries/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E8%BE%83%E5%B0%91%E7%9A%84%E5%88%86%E5%8C%BA%E4%B9%9F%E6%8A%A5%E9%94%99too-many-range-table-entries/</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;postgresql中update执行语句报错&lt;code&gt;too many range table entries&lt;/code&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:#66d9ef"&gt;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLTAB &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#66d9ef"&gt;update&lt;/span&gt;	LZLTAB &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;	STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	FILE_ID &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;	DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;localtimestamp&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;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;	id &lt;span style="color:#66d9ef"&gt;from&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;如果把update改写成select，可以执行成功&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;postgresql中update执行语句报错&lt;code&gt;too many range table entries&lt;/code&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:#66d9ef"&gt;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLTAB &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#66d9ef"&gt;update&lt;/span&gt;	LZLTAB &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;	STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	FILE_ID &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;	DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;localtimestamp&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;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;	id &lt;span style="color:#66d9ef"&gt;from&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;如果把update改写成select，可以执行成功&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;	id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt;	LZLTAB &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt;	id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#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; 	LZLTAB &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt;	id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id	&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; t)
&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; 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;8723&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;06&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&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;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;161687&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;p&gt;主键和分区是这样，分区总共有400个&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Partition &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt;: RANGE (partition_key)
&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;pk_lzl&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, partition_key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Partitions: lzl_p20230601 &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;20230601&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230602&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_p20230602 &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;20230602&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230603&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_p20230603 &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;20230603&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230604&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;sql逻辑有很多优化点，但是这里不讨论优化。重点是分析为什么update会报错，和为什么select和update会有区别。
执行explain update报错如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (selec tid &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; LZLTAB &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#66d9ef"&gt;update&lt;/span&gt; LZLTAB &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;STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FILE_ID &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;DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;localtimestamp&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;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&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;ERROR: &lt;span style="color:#ae81ff"&gt;54000&lt;/span&gt;: too many range &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; entries
&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;: add_rte_to_flat_rtable, setrefs.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;451&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;18341&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;171&lt;/span&gt; ms (&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;341&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卡了18秒，然后报错&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%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;报错直接抛出了源码的位置&lt;code&gt;LOCATION: add_rte_to_flat_rtable, setrefs.c:451 &lt;/code&gt;，直接找到该源码&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/backend/optimizer/plan/setrefs.c&lt;/code&gt;
其注释是说setrefs.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:#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; *Post-processing of a completed plan tree: fix references to subplan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *	 vars, compute regproc values for operators, etc
&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;找到第451行的函数：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * Add (a copy of) the given RTE to the final rangetable
&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; * In the flat rangetable, we zero out substructure pointers that 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; * needed by the executor; this reduces the storage space and copying cost
&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 cached plans. We keep only the ctename, alias and eref Alias fields,
&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 are needed by EXPLAIN, and the selectedCols, insertedCols,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * updatedCols, and extraUpdatedCols bitmaps, which are needed 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; * executor-startup permissions checking and for trigger event checking.
&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;add_rte_to_flat_rtable&lt;/span&gt;(PlannerGlobal &lt;span style="color:#f92672"&gt;*&lt;/span&gt;glob, RangeTblEntry &lt;span style="color:#f92672"&gt;*&lt;/span&gt;rte)
&lt;/span&gt;&lt;/span&gt;&lt;span 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;	 * Check for RT index overflow; it&amp;#39;s very unlikely, but if it did 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;	 * the executor would get confused by varnos that match the special varno
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	 * values.
&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;IS_SPECIAL_VARNO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;list_length&lt;/span&gt;(glob&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;finalrtable)))
&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;(ERROR,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				(&lt;span style="color:#a6e22e"&gt;errcode&lt;/span&gt;(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
&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;too many range table entries&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;errmsg()就是第451行。add_rte_to_flat_rtable()看注释跟RTE有关，什么RTE呢？下面再分析。
报错的判断是&lt;code&gt;IS_SPECIAL_VARNO()&lt;/code&gt;，直接搜索该函数，在&lt;code&gt;src/include/nodes/primnodes.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; * Var - expression node representing a variable (ie, a table column)
&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; * In the parser and planner, varno and varattno identify the semantic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * referent, which is a base-relation column unless the reference is to a join
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * USING column that isn&amp;#39;t semantically equivalent to either join input column
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * (because it is a FULL join or the input column requires a type coercion).
&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 those cases varno and varattno refer to the JOIN RTE. (Early 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; * planner, we replace such join references by the implied expression; but up
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * till then we want join reference Vars to keep their original identity 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; * query-printing purposes.)
&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;#define INNER_VAR		65000	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to inner subplan */&lt;/span&gt;&lt;span style="color:#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 OUTER_VAR		65001	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to outer subplan */&lt;/span&gt;&lt;span style="color:#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 INDEX_VAR		65002	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to index column */&lt;/span&gt;&lt;span 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;#define IS_SPECIAL_VARNO(varno)		((varno) &amp;gt;= INNER_VAR)&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;In those cases varno and varattno refer to the JOIN RTE&lt;/em&gt;。varno与RTE有关系。
然后&lt;code&gt;varno&amp;gt;=65000&lt;/code&gt;时，会抛出报错。（这里不扩展&lt;code&gt;INNER_VAR&lt;/code&gt;,&lt;code&gt;OUTER_VAR&lt;/code&gt;,&lt;code&gt;INDEX_VAR&lt;/code&gt;的区别，因为他们的值差别不大，不影响我们继续分析）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是RTE？&lt;/strong&gt;
在执行计划源码中的各个位置都能找到RTE（rangetable或RangeTblEntry）的描述，并且报错也很明显&lt;code&gt;ERROR: 54000: too many range table entries&lt;/code&gt;也是说的RTE。那么什么是RTE？
在&lt;code&gt;src/include/nodes/parsenodes.h&lt;/code&gt;中有一段对RTE的描述&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; * RangeTblEntry -
&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 range table is a List of RangeTblEntry nodes.
&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; *	 A range table entry may represent a plain relation, a sub-select 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; *	 FROM, or the result of a JOIN clause. (Only explicit JOIN syntax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *	 produces an RTE, not the implicit join resulting from multiple FROM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *	 items. This is because we only need the RTE to deal with SQL features
&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 outer joins and join-output-column aliasing.) Other special
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *	 RTE types also exist, as indicated by RTEKind.
&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 that we consider RTE_RELATION to cover anything that has a 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; *	 entry. relkind distinguishes the sub-cases.
&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;简单的说，RTE是执行计划中的“表”，可以是具体的表也可以是生成类的“表”，比如子查询、join结果等等。RTE超出限制65000，也就是说执行计划中生成了太多的RTE。&lt;/p&gt;

&lt;h2 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%9f%a5%e7%9c%8bupdate%e7%9a%84%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;由于我们知道了RTE的啥，所以查看sql的执行计划可能会有所帮助。但是由于源sql（400个分区）没有生成执行计划，我们创建一个30个分区的表，期待它能explain出来，然后观察它的执行计划。
30个分区的表执行相同的update语句&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#66d9ef"&gt;update&lt;/span&gt; lzl &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;STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FILE_ID &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;DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;localtimestamp&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;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&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;生成的执行计划如下&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; 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;Update&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;4980&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;600&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3042&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;on&lt;/span&gt; lzl_p20230601 lzl_1
&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;on&lt;/span&gt; lzl_p20230602 lzl_2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;on&lt;/span&gt; lzl_p20230630 lzl_30
&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 Semi &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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;166&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;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3042&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (lzl_1.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; t.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; lzl_p20230601 lzl_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;10&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2912&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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;155&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;30&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; Subquery Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t (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;155&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;30&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#f92672"&gt;-&amp;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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;154&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;30&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;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;154&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;30&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;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; lzl_p20230601_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230601 lzl_32 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&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; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; lzl_p20230602_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230602 lzl_33 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;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; lzl_p20230630_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230630 lzl_61 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; Hash Semi &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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;166&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;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3042&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (lzl_30.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; t_29.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; lzl_p20230630 lzl_30 (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;10&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2912&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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;155&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;30&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; Subquery Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; t_29 (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;155&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;30&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&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:#f92672"&gt;-&amp;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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;154&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;30&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;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;154&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;30&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;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; lzl_p20230601_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230601 lzl_931 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&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; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; lzl_p20230602_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230602 lzl_932 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;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; lzl_p20230630_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230630 lzl_960 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;2041&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;执行计划非常长，总共有2041行。这个执行计划非常笨，每个分区在更新的时候，都把谓词条件在分区表中运行了一次，由于sql没有分区键，每次运行又扫描了所有分区。本身30个分区的分区表，每个分区扫描了30次，总共扫描900次分区。
从执行计划也能看到RTE表刚开始有30个，分配给update直到lzl_30；后面每次hash匹配时每个分区扫描也分配了30个RTE，比如lzl_1对应的hash下的分区扫描从lzl_32到lzl_61。这里为什么是32而不是31？因为整个分区扫描是一个子查询也是一个RTE，为t(所有的为t,t1-t_29)，也是总共30个。所以执行计划中生成的RTE表总共有30+30+30*30=960个。&lt;/p&gt;
&lt;p&gt;如果用select来看执行计划，发现跟update的执行计划有很大的不同&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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:#66d9ef"&gt;select&lt;/span&gt; STATUS ,FILE_ID ,DATE_UPDATED &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; t);&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; Hash Semi &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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;467&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;05&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;90&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;98&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (lzl.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; lzl_31.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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;309&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;600&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;106&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; lzl_p20230601 lzl_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;10&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;106&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; lzl_p20230602 lzl_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;10&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;106&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230630 lzl_30 (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;10&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;106&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;155&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;155&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;30&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;Limit&lt;/span&gt; (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;154&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;30&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;14&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;154&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;30&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;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; lzl_p20230601_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230601 lzl_32 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&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; &lt;span style="color:#66d9ef"&gt;Only&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; lzl_p20230602_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230602 lzl_33 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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;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; lzl_p20230630_pkey &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl_p20230630 lzl_61 (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;8&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: (id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#ae81ff"&gt;96&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;没有反复（笛卡尔集式地）访问表，RTE只到了61个。这也是为什么400个分区的select可以查询出来的原因，因为400*400次访问实在太多了。
所以关于之前的sql，update执行报错，而select正常的情况，可以得出结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;400个分区的select，它的执行计划中的RTE有801个，没超过&lt;code&gt;INNER_VAR&lt;/code&gt;的值65000，它可以生成执行计划并且执行&lt;/li&gt;
&lt;li&gt;400个分区的update，它的执行计划中的RTE有160160400个，远远超过&lt;code&gt;INNER_VAR&lt;/code&gt;的值65000，不能成功生成执行计划，抛出RTE超限的报错。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原因分析的差不多了，但是select和update的执行计划差别很大，仍然感到疑惑。下面横向对比oracle和mysql的执行计划，看看有什么差别。&lt;/p&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%e8%a1%8c%e4%b8%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;oracle库创建分区表，并使用本地索引&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; lzl (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id number &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; partition_key number &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;)
&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 (partition_key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARTITION lzl_p20230601 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230602&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARTITION lzl_p20230602 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230603&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;PARTITION lzl_p20230630 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;20230631&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;index&lt;/span&gt; PKLZL &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzl(id, partition_key) &lt;span style="color:#66d9ef"&gt;local&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; lzl &lt;span style="color:#66d9ef"&gt;add&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; pklzl &lt;span style="color:#66d9ef"&gt;primary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; (id, partition_key) &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;index&lt;/span&gt; pklzl;&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;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; rownum&lt;span style="color:#f92672"&gt;&amp;lt;=&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:#66d9ef"&gt;select&lt;/span&gt; STATUS ,FILE_ID ,DATE_UPDATED &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&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;


&lt;img src="https://lastdba.com/img/csdn/e6b4077b9290.png" alt="image.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;&lt;span style="color:#66d9ef"&gt;update&lt;/span&gt; lzl &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;STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FILE_ID &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;DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sysdate
&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; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; rownum&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&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/35e2fc036d9f.png" alt="image.png" /&gt;
oracle里，select和update都使用了nest loop，访问所有分区partition range all，所以oracle无论是select和update，t表为驱动表，因为是in所以结果进行了排序去重，所以oracle的执行计划不是30*30次访问，而是跟驱动表里的结果集有关，如果是n条数据，那么访问n*30次分区。因为驱动表t没有什么数据，所以这个执行计划没什么问题。&lt;/p&gt;

&lt;h3 class="relative group"&gt;mysql的行为
 &lt;div id="mysql的行为" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%84%e8%a1%8c%e4%b8%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;因为mysql只支持本地索引，所以直接建主键就行了&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; test (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id bigint &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; 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&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;BY&lt;/span&gt; RANGE (partition_key) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARTITION lzl_p20230601 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;20230602&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARTITION lzl_p20230602 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;20230603&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARTITION lzl_p20230630 &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;THAN&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;20230631&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; lzl &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; pklzl(id,partition_key);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;mysql从5.7开始执行计划会显示扫描了哪些分区，这里的版本是8.0的。
select的执行计划：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;&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;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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; STATUS ,FILE_ID ,DATE_UPDATED &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; t);
&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:#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; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; select_type &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; partitions &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; possible_keys &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; key_len &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; filtered &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Extra &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:#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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;derived3&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:#66d9ef"&gt;ALL&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:#ae81ff"&gt;2&lt;/span&gt; &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Start&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;temporary&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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl_p20230601,lzl_p20230602,lzl_p20230603,lzl_p20230604,lzl_p20230605,lzl_p20230606,lzl_p20230607,lzl_p20230608,lzl_p20230609,lzl_p20230610,lzl_p20230611,lzl_p20230612,lzl_p20230613,lzl_p20230614,lzl_p20230615,lzl_p20230616,lzl_p20230617,lzl_p20230618,lzl_p20230619,lzl_p20230620,lzl_p20230621,lzl_p20230622,lzl_p20230623,lzl_p20230624,lzl_p20230625,lzl_p20230626,lzl_p20230627,lzl_p20230628,lzl_p20230629,lzl_p20230630 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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; t.id &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;End&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;temporary&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:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; DERIVED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl_p20230601,lzl_p20230602,lzl_p20230603,lzl_p20230604,lzl_p20230605,lzl_p20230606,lzl_p20230607,lzl_p20230608,lzl_p20230609,lzl_p20230610,lzl_p20230611,lzl_p20230612,lzl_p20230613,lzl_p20230614,lzl_p20230615,lzl_p20230616,lzl_p20230617,lzl_p20230618,lzl_p20230619,lzl_p20230620,lzl_p20230621,lzl_p20230622,lzl_p20230623,lzl_p20230624,lzl_p20230625,lzl_p20230626,lzl_p20230627,lzl_p20230628,lzl_p20230629,lzl_p20230630 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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; const &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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;update的执行计划：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;with&lt;/span&gt; t &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzl &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8723&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;limit&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;update&lt;/span&gt; lzl &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; STATUS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;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:#f92672"&gt;-&amp;gt;&lt;/span&gt; FILE_ID &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:#f92672"&gt;-&amp;gt;&lt;/span&gt; DATE_UPDATED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;localtimestamp&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; id &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; t);
&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:#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; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; select_type &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; partitions &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; possible_keys &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; key_len &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; filtered &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Extra &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:#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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;derived3&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:#66d9ef"&gt;ALL&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:#ae81ff"&gt;2&lt;/span&gt; &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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Start&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;temporary&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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;UPDATE&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl_p20230601,lzl_p20230602,lzl_p20230603,lzl_p20230604,lzl_p20230605,lzl_p20230606,lzl_p20230607,lzl_p20230608,lzl_p20230609,lzl_p20230610,lzl_p20230611,lzl_p20230612,lzl_p20230613,lzl_p20230614,lzl_p20230615,lzl_p20230616,lzl_p20230617,lzl_p20230618,lzl_p20230619,lzl_p20230620,lzl_p20230621,lzl_p20230622,lzl_p20230623,lzl_p20230624,lzl_p20230625,lzl_p20230626,lzl_p20230627,lzl_p20230628,lzl_p20230629,lzl_p20230630 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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; t.id &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;End&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;temporary&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:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; DERIVED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzl_p20230601,lzl_p20230602,lzl_p20230603,lzl_p20230604,lzl_p20230605,lzl_p20230606,lzl_p20230607,lzl_p20230608,lzl_p20230609,lzl_p20230610,lzl_p20230611,lzl_p20230612,lzl_p20230613,lzl_p20230614,lzl_p20230615,lzl_p20230616,lzl_p20230617,lzl_p20230618,lzl_p20230619,lzl_p20230620,lzl_p20230621,lzl_p20230622,lzl_p20230623,lzl_p20230624,lzl_p20230625,lzl_p20230626,lzl_p20230627,lzl_p20230628,lzl_p20230629,lzl_p20230630 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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; const &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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;mysql的2个执行计划都一致。但是执行计划驱动表选择有问题，const的应该为驱动表扫描次数会更少。&lt;/p&gt;

&lt;h2 class="relative group"&gt;BUG?
 &lt;div id="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="#bug" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;bug描述
 &lt;div id="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="#bug%e6%8f%8f%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://postgrespro.com/list/thread-id/2482006" target="_blank" rel="noreferrer"&gt;https://postgrespro.com/list/thread-id/2482006&lt;/a&gt;
通过报错很容易就能搜到这个bug。这个bug还是德哥在2020年提交的，后面是两个源码大佬对这个bug的讨论，讨论内容比较长，总结一下：pg并不支持无限制的分区表，这在真实世界中也是能理解的，如果分区过多性能可能会急速下降。但是社区还是认为需要调整这个限制，并对源码中的&lt;code&gt;INNER_VAR&lt;/code&gt;、&lt;code&gt;Var.varno&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%af%af%e5%af%bc%e6%80%a7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;这个bug标题有一定的误导性，&lt;em&gt;BUG #16302: too many range table entries - when count partition table(65538 childs)&lt;/em&gt;
bug看上去说分区表的分区不能超过65538个，在讨论中也有&lt;em&gt;PG can handle up to 64K relations in a query&lt;/em&gt;，一个查询不能有超过64K的relation。
这个就很奇怪，因为我这里的表是400个分区，然后就抛出报错了。实际上上面两个描述不太准确。因为64K的限制指的是执行计划中“表”，不全等于真实的表。当然如果表或者分区已经超过这个数，那么当然会有问题。但是如果没有超过64K，也可能是有问题的，就像我这里的案例一样，它只有400个分区。&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%bf%ae%e5%a4%8d" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;bug提交的是12.2版本，我的环境是13.2版本的。
这个bug在pg15中修复，&lt;code&gt;src/include/nodes/primnodes.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 INNER_VAR		(-1)	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to inner subplan */&lt;/span&gt;&lt;span style="color:#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 OUTER_VAR		(-2)	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to outer subplan */&lt;/span&gt;&lt;span style="color:#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 INDEX_VAR		(-3)	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* reference to index column */&lt;/span&gt;&lt;span style="color:#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 ROWID_VAR		(-4)	&lt;/span&gt;&lt;span style="color:#75715e"&gt;/* row identity column during planning */&lt;/span&gt;&lt;span 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;#define IS_SPECIAL_VARNO(varno)		((int) (varno) &amp;lt; 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;跟社区讨论的一样，15中不仅把几个VAR都改成了负数，还把varno转换成了32位(40亿），之前是16位的（也就是65536）。
而在抛出报错的函数中，&lt;code&gt;src/backend/optimizer/plan/setrefs.c&lt;/code&gt;中的&lt;code&gt;add_rte_to_flat_rtable()&lt;/code&gt;函数中的报错代码已经被删除了！整个15的源码都没有&lt;code&gt;too many range table entries&lt;/code&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;pg对于分区表的优化还有提升空间。pg对于分区表的分区，跟oracle、mysql不一样，它仍然子分区当成普通表来处理，而oracle只是把子分区当成一个段来处理，跟表是有差别的。这也导致pg在生产分区表执行计划时把每一个分区的访问方式都写了出来（在不会裁剪的情况下），分区特别多时执行计划会非常的长；而oracle只需要写&lt;code&gt;partition range all&lt;/code&gt;就行了；mysql也会打印所有分区，但是不会像pg那样把每个分区的访问当成一个子查询，从而降低了执行计划的复杂度。&lt;/li&gt;
&lt;li&gt;即使分区没有达到64K，也可能报错&lt;code&gt;too many range table entries&lt;/code&gt;。这个限制其实是执行计划RTE个数，而不是分区个数（当然分区达到这个数，RTE也到达了，就像上面说的，pg打印了所有分区的访问方式）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;too many range table entries&lt;/code&gt;报错在pg15解决&lt;/li&gt;
&lt;li&gt;如果是15以下的版本，确实不要建太多的分区！当然也可以利用分区裁剪来减少分区的访问，就像这个案例，把where逻辑中加上分区键条件就可以了。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>另一个世界的人</title><link>https://lastdba.com/2024/08/12/%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%B8%96%E7%95%8C%E7%9A%84%E4%BA%BA/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%B8%96%E7%95%8C%E7%9A%84%E4%BA%BA/</guid><description>&lt;p&gt;​


&lt;img src="https://lastdba.com/img/csdn/13ea4ca5d98b.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="#%e4%bc%91%e5%81%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        赶在假期无效前，休了个长假回了趟老家。不仅是为了逃离工作的繁忙，也为了看望老家的婆婆爷爷。回趟老家对于我们这种社会人来说确实太难了，如果只是周末回去也就休息一天就得往回赶，太累。自己的假期本来就不多，如果有假期，社会人都想着开车出去看看风景或者干脆在家里呆几天哪也不去，一般也不会想到利用稀有的假期回老家看望老人。
        比较讽刺的是，回去看望婆婆爷爷我休的是育儿假，不是什么养老假。这个世界好像没有”养老假“这个东西，只有探亲假。虽然法定是有”探亲假“这个东西的，但是先不说探亲假不是针对专门看望老年人的假，就探亲假那个极长的定语，对于绝大部分人来说，就是没有探亲假。
        育儿假不在家育儿，却去看望老人，我想一般人肯定干不出来，是不是只有我这种奇葩才能干得出来 ..至少我是这么想的：养育子女和照顾老人同样重要，不应该厚此薄彼。社会和社会人更重视前者。无论怎样，我还是想回去陪陪老人家，看看老两口每天在干嘛，以怎样的方式生活？是否生活上有困难？怎样看待困难？于是我就这样一个人回去了。&lt;/p&gt;</description><content:encoded>&lt;p&gt;​


&lt;img src="https://lastdba.com/img/csdn/13ea4ca5d98b.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="#%e4%bc%91%e5%81%87" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        赶在假期无效前，休了个长假回了趟老家。不仅是为了逃离工作的繁忙，也为了看望老家的婆婆爷爷。回趟老家对于我们这种社会人来说确实太难了，如果只是周末回去也就休息一天就得往回赶，太累。自己的假期本来就不多，如果有假期，社会人都想着开车出去看看风景或者干脆在家里呆几天哪也不去，一般也不会想到利用稀有的假期回老家看望老人。
        比较讽刺的是，回去看望婆婆爷爷我休的是育儿假，不是什么养老假。这个世界好像没有”养老假“这个东西，只有探亲假。虽然法定是有”探亲假“这个东西的，但是先不说探亲假不是针对专门看望老年人的假，就探亲假那个极长的定语，对于绝大部分人来说，就是没有探亲假。
        育儿假不在家育儿，却去看望老人，我想一般人肯定干不出来，是不是只有我这种奇葩才能干得出来 ..至少我是这么想的：养育子女和照顾老人同样重要，不应该厚此薄彼。社会和社会人更重视前者。无论怎样，我还是想回去陪陪老人家，看看老两口每天在干嘛，以怎样的方式生活？是否生活上有困难？怎样看待困难？于是我就这样一个人回去了。&lt;/p&gt;
&lt;p&gt;路的尽头.
        老两口生活的地方，是我从小长大的地方。那个地方也很隐蔽，要从大路拐进一条山路，走很久，一直走到路的尽头。像是一个与世隔绝的地方，到了那里，就感觉与外面的世界的联系好像不存在了。       &lt;/p&gt;
&lt;p&gt;         那里其实也不是我的老家，不过我更喜欢这样称呼那里。那是一片矿山，因为是依山而建，矿山很有立体感，立体到对开发矿山的前辈设计感到震惊。我至今不太清楚怎么描述这个地方的行政级别，它不是村，也不是镇，比村更现代，比镇更小。小时候我认为这个地方很大，现在发现只需要10分钟就可以把这片矿逛完。&lt;/p&gt;
&lt;p&gt;        整个地方以煤矿作为经济支柱，曾经繁荣过，不过现在已经萧条多了。现在矿区仍有会下井的矿工，不过在矿山的生活区已经看不到像我这样的年轻人了。矿山有个小学，在我读小学的时候，一个年级大概有70个人，现在只有7个人。&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%a3%9f%e7%89%a9" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        小时候菜市场还是比较热闹的。我记得卖鸡鸭的地方，小贩会用黑乎乎像沥青一样的东西浸没整只鸡，然后再拔毛，卖鸡鸭地方总是脏兮兮的。现在菜市场已经没有卖新鲜肉的了，只能买到附近农户自己种的蔬菜。如果要买新鲜肉只有到村上去赶集或者去搭班车去城里买。&lt;/p&gt;
&lt;p&gt;        因为老两口生活特别节俭，刚开始我还比较担心他们生活过于朴素，可能搞得每天都是米饭和素菜。这次我回去时，没有告诉他们我具体什么时间到，当我到家时，发现他们还买了卤鸭子，我还是很欣慰的。我回去老两口很高兴，就三个人每天都弄了5、6个菜，我甚至有点怀疑自己是不是回去陪他们，而是回去添麻烦的。&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="#%e4%b8%ad%e8%8d%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        我这次回去，发现一个事实：老年人对药物的依赖性极强。他们的药箱里总有各式各样的药物，西药、中药、感冒药、发炎药、药膏、保健药一大堆。自己感觉身体哪有问题就拿自己认为有用的药。我这次回去鼻炎犯了（老毛病了），不停的打喷嚏流鼻涕，他们不停的劝我吃点感冒药，推荐我吃感冒灵或者头孢，我可能说了不下十次，我这个是鼻炎，不是感冒。他们当然也不知道这种鼻炎要怎么治，然后继续劝我我吃感冒药&lt;/p&gt;
&lt;p&gt;        有次我带老人家进城，除了去超市进购，更重要的就是买药。买药也分为中药和西药。&lt;/p&gt;
&lt;p&gt;        中药是在一个云南中药店里面买的，店老板一头圆寸发型，黑色T恤，银色的项链，褐色的珠子手链，看上去很壮实，他这一身社会大哥形象我都不敢他大声讲话，不过我爷爷好像并没有注意到这些。店里基本都是我说不出名字的中药，按斤卖，还挺贵，不是一般中药的那种。明显我爷爷是这里的老顾客了，老板是认识他的，不过看上去我爷爷他也不会选药，“老板，你按照我的身体状况给我称300块钱的”。于是老板这里抓了点，那里抓了点，最后全部打成粉。&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="#%e8%a5%bf%e8%8d%af" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        中药买完，走了很远的地方，去药店买西药。那个药店可能是他们为数不多认识的药店。&lt;/p&gt;
&lt;p&gt;        那个药店绝大部分药都是无法报销的，在很里面的一个很小很简陋的房间里面，才摆着一小部分可以报销的药。我看了一圈，基本不认识，都是化学分子式命名的药，完全看不懂。只有一些感冒灵、枇杷露这类药算认识的。爷爷选药同样也陷入了选择困难的处境。他认识头孢，但是药店小妹说头孢没有，他有点生气。他对小妹说：“你要没有好点的药呢？”（好点的药？我尝试理解这句话），小妹不知道从哪拿出来一个红色盒子的精致包装保健药，爷爷他看不清盒子上面的字，他让我给他念一下，看看这是治什么的。我拿来一看，这东西啥都治，就没念，把它还给了小妹。最后也只是选了一点治感冒咳嗽常见的药。&lt;/p&gt;
&lt;p&gt;       爷爷一路上反复跟我说，他一年有170块钱的医保可以报销 ，能看出来他非常想把这170块钱花掉，给家里囤点药。这也是为什么会去买西药店买药的原因，也是为什么要走到那个可以报销的药店。   &lt;/p&gt;
&lt;p&gt;        不过结账的时候遇到一些困难。结账小妹从刚开始表情就不太好，她拿过药说了一堆东西，我都没听懂，我爷爷也明显没听懂。最后说的“这个药报不了”算是听懂了。&lt;/p&gt;
&lt;p&gt;        小妹说：“这个报销有门槛费150，你还没有缴门槛费”&lt;/p&gt;
&lt;p&gt;        爷爷说：“门槛费是不是就像以前医院收的床位费150一样？”&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;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="#%e7%a7%91%e6%8a%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        我们感叹科技发展迅速，总是有新的东西改变着人类的生活方式，让生活变的更加便利。社会人追求科技，沉浸于科技。但是对于老人来说，科技完全是另一码事。&lt;/p&gt;
&lt;p&gt;        老年人生活的方方面面，设计到科技的东西真的非常非常少。最最常用的，就是手机，而且是智能手机。他们好像很适应抖音类APP所带来的快节奏娱乐信息，他们也会在睡觉前玩会手机刷刷抖音再睡觉（他们用的大概率不是抖音，而是另外一些有推荐短视频的软件）。&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="#%e6%97%85%e6%b8%b8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        带着老俩口出去旅游是我的这次回去的重要任务。本来我是没有这个计划的，我只想回去把自己放空，呼吸两口新鲜空气，就呆在那里感受一下慢时间。不过他们挺喜欢出去玩的，我一回去爷爷就主动跟我说可以开车带他们出去耍一下。&lt;/p&gt;
&lt;p&gt;        我们先后去了朱德故里、阆中古城、南充，玩了2天一夜。跟老年人出去玩本身要考虑的东西会更多，不能坐太久的车，也不能走太多的路。这样其实也玩不到什么东西。不过他们的旅游观念跟我们不太一样，他们更倾向于打卡，更重视“来过”这个价值，所以一定要在写这地名的打卡点拍照~&lt;/p&gt;
&lt;p&gt;        他们也更倾向于人多的地方，而不是人少的风景优美的地方。在阆中的时候，他们明显更喜欢古城里面，人多嘈杂热闹的感觉，还会姑姑视频说“我们在阆中！！”（重语气），笑得合不拢嘴。而在白塔山（可以开车上去，很适合老年人）上看阆中城全景的时候，我还沉浸于what a view的场景中，婆婆看了2分钟拍了2张照就没有看了。我说你看看风景撒，多漂亮，好不容易上来，她说，我看了呀。&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%a3%9a%e5%ad%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;        平时爷爷常去小公园看别人打牌，婆婆去打麻将，不打钱那种。
        除了打牌，最常呆的地方就是楼下的棚子。几个几家人不要的凳子椅子放在棚子下面，中间一个炉子，冬天会烧点柴火。楼上楼下都是认识的，都是爷爷奶奶辈，跟我婆婆爷爷关系很好，邻里邻居没事就会坐在一起摆龙门阵，这也是小区（其实也不是小区，就是2栋楼）最重要的社交场所。
        一天晚上，我坐在棚子里听他们聊天。有个婆婆说：“你这孙子好哦，请假回来陪老人家。我们都说你孙子好。”说的我都不好意思，不过想想还是让这个评价留在这几个老人的脑海里吧。&lt;/p&gt;
&lt;p&gt;        一个爷爷说：“我跟xx他们家里人说，你们一个月回来一次，陪陪老年人，不用给他们钱，他们拿这钱有什么用，他们可以过日子。但是你们长大了，走了，长时间没有陪伴他们会感到孤独。“我想，这老爷爷还挺明白事儿。他又说道：“一次某某死了，他家人都回来办葬礼，他们回来给他端水果端吃的，有什么用？他吃到没有嘛？说白了，这些是做给我们看的。人都走了，做这些都没用”。哟喂，这老年人是真懂。&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="#%e6%9d%82%e6%83%b3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;写于-2023-04&lt;/p&gt;
&lt;p&gt;        “婆婆”这个称呼，在我这一代还保留着，我的下一代，已经不叫“婆婆”，而是叫“奶奶”了。也许“婆婆”是这个族系最后的一次称呼，may be the last call。就让它保存在这篇文章里吧。&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>没有阻塞为什么partition of创建子分区很慢？</title><link>https://lastdba.com/2024/08/12/%E6%B2%A1%E6%9C%89%E9%98%BB%E5%A1%9E%E4%B8%BA%E4%BB%80%E4%B9%88partition-of%E5%88%9B%E5%BB%BA%E5%AD%90%E5%88%86%E5%8C%BA%E5%BE%88%E6%85%A2/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%B2%A1%E6%9C%89%E9%98%BB%E5%A1%9E%E4%B8%BA%E4%BB%80%E4%B9%88partition-of%E5%88%9B%E5%BB%BA%E5%AD%90%E5%88%86%E5%8C%BA%E5%BE%88%E6%85%A2/</guid><description>&lt;h4 class="relative group"&gt;create table.. partition of语句慢分析
 &lt;div id="create-table-partition-of语句慢分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#create-table-partition-of%e8%af%ad%e5%8f%a5%e6%85%a2%e5%88%86%e6%9e%90" 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:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;063&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;authentication&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;41364668&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;connection authorized: user=user1 database=dblzl&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;079&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;41364669&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;statement: -- a86fae372f73414bbe1af18213a47beb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/*a86fae372f73414bbe1af18213a47beb */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;create table if not exists table1_partition_p2406 partition of table1 for values from (&amp;#39;2024-06-01 00:00:00&amp;#39;) to (&amp;#39;2024-07-01 00:00:00&amp;#39;); &amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;38&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;555&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;CREATE TABLE&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;duration: 2129483.549 ms&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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;user1这个用户在22:02:59连接进入数据库后，立即就执行了一个&lt;code&gt;create table.. partition of..&lt;/code&gt;的语句，直到22:38:28才跑完。中间的日志忽略了，一大堆会话阻塞信息，阻塞源均是125889这个会话。
被阻塞的会话类似如下：&lt;/p&gt;</description><content:encoded>
&lt;h4 class="relative group"&gt;create table.. partition of语句慢分析
 &lt;div id="create-table-partition-of语句慢分析" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#create-table-partition-of%e8%af%ad%e5%8f%a5%e6%85%a2%e5%88%86%e6%9e%90" 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:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;063&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;authentication&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;41364668&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;connection authorized: user=user1 database=dblzl&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;079&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;idle&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;41364669&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;statement: -- a86fae372f73414bbe1af18213a47beb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/*a86fae372f73414bbe1af18213a47beb */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;create table if not exists table1_partition_p2406 partition of table1 for values from (&amp;#39;2024-06-01 00:00:00&amp;#39;) to (&amp;#39;2024-07-01 00:00:00&amp;#39;); &amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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:#ae81ff"&gt;2024&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;38&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;28&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;555&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dblzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;30.88.79.3:37423&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66461213&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ebc1,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;CREATE TABLE&amp;#34;&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;05&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:#ae81ff"&gt;22&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; CST,&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;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;duration: 2129483.549 ms&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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;user1这个用户在22:02:59连接进入数据库后，立即就执行了一个&lt;code&gt;create table.. partition of..&lt;/code&gt;的语句，直到22:38:28才跑完。中间的日志忽略了，一大堆会话阻塞信息，阻塞源均是125889这个会话。
被阻塞的会话类似如下：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;process &lt;span style="color:#ae81ff"&gt;33569&lt;/span&gt; still waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; RowExclusiveLock &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; relation &lt;span style="color:#ae81ff"&gt;53733&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;17073&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;after&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;048&lt;/span&gt; ms&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;Process holding the &lt;span style="color:#66d9ef"&gt;lock&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;125889&lt;/span&gt;. Wait queue: &lt;span style="color:#ae81ff"&gt;33569&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添加分区时，会在主表上加8级锁，然后阻塞分区表上的所有操作。正常来说partition of添加分区是非常快的，锁也会立即释放。不过如果分区表上有长事务，那么这个主表上的8级锁得等着，然后就造成后续的阻塞。
盗&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171591065916800225570929%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=171591065916800225570929&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-132525655-null-null.nonecase&amp;amp;utm_term=%E5%88%86%E5%8C%BA%E8%A1%A8&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;自己的图&lt;/a&gt;：



&lt;img src="https://lastdba.com/img/csdn/6c7f70fc3b60.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;然而这个案例表上没有长事务，partition of添加分区却执行了35分钟。
从历史的进程信息可以看出这个进程是D状态，是有问题的。刚开始以为是内存、磁盘这些问题，排查了一圈都正常。&lt;/p&gt;
&lt;p&gt;然而这个问题很好复现，直接在仿真环境上跑一个&lt;code&gt;create table parttion of&lt;/code&gt;执行会非常慢。pg_stat_activity会话信息显示，该语句等待在IO上：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;wait_event_type &lt;span style="color:#f92672"&gt;|&lt;/span&gt; IO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wait_event	 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; DataFileRead
&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; active
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;query		&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; xxx partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; xx &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;2025-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;2025-06-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;p&gt;strace追踪进程信息发现，该进程大量的读取一个文件&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;pread64(&lt;span style="color:#ae81ff"&gt;53&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;\22\2\0\0\220w\321&amp;gt;\0\0\5\0\24\0018\1\0 \4 \0\0\0\0\200\237\0\1\310\236p\1&amp;#34;&lt;/span&gt;..., &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;863485952&lt;/span&gt;) &lt;span style="color:#f92672"&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;p&gt;通过文件描述符53找到该文件&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;proc&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;356174&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;fd] ll &lt;span style="color:#f92672"&gt;|&lt;/span&gt;grep &lt;span style="color:#ae81ff"&gt;53&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwx&lt;span style="color:#75715e"&gt;------ 1 postgres postgres 64 May 17 15:34 53 -&amp;gt; /lzl/pglzl/data/base/17076/25883&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;oid2name &lt;span style="color:#f92672"&gt;-&lt;/span&gt;d lzldb &lt;span style="color:#f92672"&gt;-&lt;/span&gt;f &lt;span style="color:#ae81ff"&gt;25883&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; &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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filenode				 &lt;span style="color:#66d9ef"&gt;Table&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; &lt;span style="color:#ae81ff"&gt;25883&lt;/span&gt; table_partition_default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;最后定位这个表table_partition_default&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; table_partition_default
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;: table_partition_default &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;Partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt;: (&lt;span style="color:#66d9ef"&gt;NOT&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;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2022-05-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;OR&lt;/span&gt; ((date_created &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2022-05-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; (da
&lt;/span&gt;&lt;/span&gt;&lt;span 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;=&amp;gt;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;dt&lt;span style="color:#f92672"&gt;+&lt;/span&gt; table_partition_default
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; relations
&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;Owner&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Persistence &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; 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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; table_partition_default &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; user1 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; permanent &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; GB &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;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;原来是default分区表，分区数据有几十GB。oracle dba可能很陌生···pg的default分区会接收不在分区范围中的数据，default分区可以保证即使没有定义到数据范围，也可以接收数据。
如果有数据存在default分区中，新分区又需要包含这部分数据，那这个游戏咋玩呢···直接报错：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;exists&lt;/span&gt; table_partition_pxxxx partition &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; table_partition &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-12 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-01-13 00: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;23514&lt;/span&gt;: updated partition &lt;span style="color:#66d9ef"&gt;constraint&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; partition &lt;span style="color:#e6db74"&gt;&amp;#34;table_partition_default&amp;#34;&lt;/span&gt; would be violated &lt;span style="color:#66d9ef"&gt;by&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; NAME: &lt;span style="color:#66d9ef"&gt;public&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; NAME: table_partition_default
&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_default_partition_contents, partbounds.&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3227&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分区的分区约束（Partition constraint）,default分区约束检查即是在做添加普通子分区时的default分区数据校验。&lt;/p&gt;
&lt;p&gt;到这原因已经很明显：
分区表新增子分区时，由于建分区的语句需要校验default分区中的数据，保证新分区数据范围与default分区的现有数据不冲突，导致&lt;code&gt;create table partition of&lt;/code&gt;读取了大量的default分区数据，新建分区一直未完成。随后阻塞扩大，业务数据无法查询和写入。&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%b0%8f%e7%bb%93%e5%92%8c%e5%bb%ba%e8%ae%ae" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;postgresql分区表使用的越来越多了，维护分区还有很多需要注意的知识点，推荐看下&lt;a href="https://blog.csdn.net/qq_40687433/article/details/132525655?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171591065916800225570929%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;amp;request_id=171591065916800225570929&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-132525655-null-null.nonecase&amp;amp;utm_term=%E5%88%86%E5%8C%BA%E8%A1%A8&amp;amp;spm=1018.2226.3001.4450" target="_blank" rel="noreferrer"&gt;PostgreSQL分区表&lt;/a&gt;，几乎面面俱到。&lt;/p&gt;
&lt;p&gt;在这个案例中，改造关键在于default分区的数据。在default改造前，不要使用partition of方式创建子分区。
default分区改造方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;detach default子分区，然后合理创建子分区，再将default表数据回插到分区表中。&lt;/li&gt;
&lt;li&gt;如有必要，可在detach且创建合理子分区后，创建一个空的default分区，以保持业务数据的连续性。&lt;/li&gt;
&lt;li&gt;注意detach跟attach不同，detach需要主表的8级锁。PG14支持detach concurrently。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如不改造default分区，应检查当前default分区的数据范围。再用attach添加子分区，会很慢，但不会阻塞读写。&lt;/p&gt;
&lt;p&gt;最后在复习下分区表新增分区最佳实践：
partition of添加子分区要申请主表的8级锁，风险还是有的。推荐attach方式为表新增子分区（分区索引也可以这么做），不会阻塞读写，完全不影响业务，可在线执行。
&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:#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:#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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果新分区还有数据的话，attach还可能比较慢，可提前创建约束来优化
&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;</content:encoded></item><item><title>如何解决索引分裂问题？</title><link>https://lastdba.com/2024/08/12/%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E7%B4%A2%E5%BC%95%E5%88%86%E8%A3%82%E9%97%AE%E9%A2%98/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E7%B4%A2%E5%BC%95%E5%88%86%E8%A3%82%E9%97%AE%E9%A2%98/</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="#%e7%b4%a2%e5%bc%95%e5%88%86%e8%a3%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;索引块快写满时就会发生索引分裂，索引分裂分为两种情况，55和91：



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


&lt;img src="https://lastdba.com/img/csdn/be40fcc99a6d.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;索引分裂和enq: TX - index contension等待事件的区别&lt;/strong&gt;
无论是55还是91，都是数据增多后索引的正常行为，索引分裂是业务数据量增大导致索引增大的&lt;strong&gt;正常现象&lt;/strong&gt;，索引放不下了自然要更多的索引块来存放数据，基本也没有只有表无索引的情况（在初始化数据的场景下，才会考虑先插入数据，再建索引）。索引分裂虽然有一定的资源消耗，但是在现在的oracle环境中也是可以很快完成的，索引过多的话才会影响插入效率。
而enq: TX - index contension这个等待就不是正常现象了。enq: TX - index contension等待表示SQL在等待正在发生分裂的索引块，本质上是DML并发过大且都在等待分裂的索引块。&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="#%e7%b4%a2%e5%bc%95%e5%88%86%e8%a3%82" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;索引块快写满时就会发生索引分裂，索引分裂分为两种情况，55和91：



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


&lt;img src="https://lastdba.com/img/csdn/be40fcc99a6d.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;索引分裂和enq: TX - index contension等待事件的区别&lt;/strong&gt;
无论是55还是91，都是数据增多后索引的正常行为，索引分裂是业务数据量增大导致索引增大的&lt;strong&gt;正常现象&lt;/strong&gt;，索引放不下了自然要更多的索引块来存放数据，基本也没有只有表无索引的情况（在初始化数据的场景下，才会考虑先插入数据，再建索引）。索引分裂虽然有一定的资源消耗，但是在现在的oracle环境中也是可以很快完成的，索引过多的话才会影响插入效率。
而enq: TX - index contension这个等待就不是正常现象了。enq: TX - index contension等待表示SQL在等待正在发生分裂的索引块，本质上是DML并发过大且都在等待分裂的索引块。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么enq: TX - index contension总是发生在顺序插入的字段上？&lt;/strong&gt;
虽然55分裂和91分裂在真实场景都是由可能的，但是enq: TX - index contension等待经常发生在91分裂的情况。因为序列、时间等字段上一般会有索引，并且经常发生顺序插入，此时最后侧的块一直都是热点块，后续的插入一直等待分裂块完成才能插入进去，此时便造成了enq: TX - index contension。UUID上一般也有索引，为什么没有造成enq: TX - index contension等待？因为UUID索引存在无序性，插入导致UUID索引分裂，也很难有后续插入的UUID值刚好也在这个分裂的索引块上。所以UUID是有索引分裂但不会形成enq等待队列从而出现enq: TX - index contension的情况。&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%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;注意我们要解决的是索引分裂等待enq: TX - index contension，而不是索引分裂本身。解决办法：
&lt;strong&gt;1.反序索引&lt;/strong&gt;
索引顺序的存放键值，反序索引刚好相反。例如一个'1111 0001&amp;rsquo;一串数字，正序索引会将它排在'0000 0002&amp;rsquo;后面；如果是反序索引，它排在'0000 0002&amp;rsquo;前面。想象一下时间字段，本身是最右热点，反序后秒、分、时排序在前，一个索引块可能包含不同月的同一秒数据，这样最右热点块基本不存在了，反序索引可以将热点打散到索引各个块上。
&lt;em&gt;局限性&lt;/em&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:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; reveridx &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; tablzl (name) REVERSE;&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.hash分区索引&lt;/strong&gt;
在普通表上创建hash分区索引，相当于表不变、把索引分区，这样最右的热点块打撒到各个分区上。比如建立一个8分区的hash分区索引，将索引分成8个segment，最右热点有8个，减缓了索引分裂问题
&lt;em&gt;局限性&lt;/em&gt;：需要改造索引；会影响索引范围查询的性能，需要抉择插入热点和查询效率问题。
等值和IN可以高效使用hash分区索引，官方文档&lt;a href="https://docs.oracle.com/cd/E11882_01/server.112/e41573/data_acc.htm#PFGRF94786" target="_blank" rel="noreferrer"&gt;原文&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Queries involving equality and &lt;code&gt;IN&lt;/code&gt; predicates on index partitioning key can efficiently use global hash partitioned index to answer queries quickly&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;但是范围查找的效率会下降，分区越多下降越多（分区越多热点缓解越明显），这显然是一个平衡选择性问题。经测试，分区8个，范围查找逻辑读提升也接近8倍。分区后在每个分区内索引仍然是有序的，聚簇因子差别不大，扫描索引的代价差别不大，但是回表的代价加大。如果普通索引一个块内有8条数据指向1个数据块，会造成1次逻辑读，hash后分别存放在8个分区，每个分区1个索引块，会造成8次逻辑读。这就是范围扫描索引性能下降的原因。
&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;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; cust_last_name_ix &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; customers (cust_last_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;GLOBAL&lt;/span&gt; PARTITION &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; HASH (cust_last_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PARTITIONS &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;&lt;strong&gt;3.利用分区将索引打散&lt;/strong&gt;
可以将表分区，创建本地索引从而达到打散最右热点的效果
&lt;strong&gt;局限性&lt;/strong&gt;：分区键不能是索引字段（如果是索引字段就没有意义了）；需要改造表；如果有SQL本身有分区字段，不会影响范围扫描的效率&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.降低并发&lt;/strong&gt;
降低并发是终极武器。索引分裂等待本质就是并发太高了，如果没有几十个以上的并发插入一般都不会有索引分裂等待。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5.修改索引块大小&lt;/strong&gt;
将索引块存放在16、32K的表空间中。这种情况理论上确实会有用，因为索引能存放的的数据更多了，分裂的情况就更少了。不过需要测试其性能，可能还有其他参数需要调整。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6.删掉索引&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="#%e8%bf%99%e4%ba%9b%e6%83%85%e5%86%b5%e4%b8%ba%e4%bb%80%e4%b9%88%e6%b2%a1%e7%94%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增加ITL事务槽&lt;/strong&gt;
索引块的事务槽也可能因为高并发而不够用，确实于索引分裂的情况有些相似，但是其等待为enq: TX - allocate ITL entry。如果有这个等待，能分析到是索引块的，就说明索引上有较高的并发，同样可以用反序索引、hash分区索引来缓解问题，也可考虑修改initrans来解决问题。不过这两个等待的根因还是不同的，索引分裂不一定会伴随事务槽问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调整索引块PCT_FREE&lt;/strong&gt;
PCTFREE表示一个数据块可用空间小于PCTFREE时，该数据块不在被记录在FREELIST中，即不能插入新数据。考虑两种情况：增加PCTFREE和减少PCTFREE。增加PCTFREE只能加剧索引分裂；减少PCTFREE看上去有效果，原理跟调整索引块大小类似，但是真实场景中PCTFREE默认是10%，已经很难再调小了，调整的效果不会很明显。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重建索引减少碎片率&lt;/strong&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%8f%82%e8%80%83" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/lihuarongaini/article/details/101299328" target="_blank" rel="noreferrer"&gt;https://blog.csdn.net/lihuarongaini/article/details/101299328&lt;/a&gt;
&lt;a href="https://docs.oracle.com/cd/E11882_01/server.112/e41573/data_acc.htm#PFGRF94786" target="_blank" rel="noreferrer"&gt;https://docs.oracle.com/cd/E11882_01/server.112/e41573/data_acc.htm#PFGRF94786&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;鸣谢：豪桑、用哥&lt;/p&gt;</content:encoded></item><item><title>事务的历史与SSI——PostgreSQL数据库技术峰会成都站分享</title><link>https://lastdba.com/2024/08/12/%E4%BA%8B%E5%8A%A1%E7%9A%84%E5%8E%86%E5%8F%B2%E4%B8%8Essipostgresql%E6%95%B0%E6%8D%AE%E5%BA%93%E6%8A%80%E6%9C%AF%E5%B3%B0%E4%BC%9A%E6%88%90%E9%83%BD%E7%AB%99%E5%88%86%E4%BA%AB/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E4%BA%8B%E5%8A%A1%E7%9A%84%E5%8E%86%E5%8F%B2%E4%B8%8Essipostgresql%E6%95%B0%E6%8D%AE%E5%BA%93%E6%8A%80%E6%9C%AF%E5%B3%B0%E4%BC%9A%E6%88%90%E9%83%BD%E7%AB%99%E5%88%86%E4%BA%AB/</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%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&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%e6%95%b0%e6%8d%ae%e5%ba%93%e6%8a%80%e6%9c%af%e5%b3%b0%e4%bc%9a%e6%88%90%e9%83%bd%e7%ab%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;近期（2023年6月17日），由中国开源软件推进联盟PG分会发起的“PostgreSQL数据库技术峰会成都站”圆满举行。我也有幸作为演讲嘉宾参加了此次峰会，收获很多。



&lt;img src="https://lastdba.com/img/csdn/09a770e6512b.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="#%e5%89%8d%e8%a8%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&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%e6%95%b0%e6%8d%ae%e5%ba%93%e6%8a%80%e6%9c%af%e5%b3%b0%e4%bc%9a%e6%88%90%e9%83%bd%e7%ab%99" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;近期（2023年6月17日），由中国开源软件推进联盟PG分会发起的“PostgreSQL数据库技术峰会成都站”圆满举行。我也有幸作为演讲嘉宾参加了此次峰会，收获很多。



&lt;img src="https://lastdba.com/img/csdn/09a770e6512b.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;（分会回顾和所有ppt下载：&lt;a href="https://mp.weixin.qq.com/s/Gby7uHVV3bR-HvROZCg46Q" target="_blank" rel="noreferrer"&gt;PPT下载来了 | PostgreSQL技术峰会成都站回顾&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="#%e6%88%91%e7%9a%84%e5%88%86%e4%ba%ab" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;我的技术分享主题为：&lt;strong&gt;数据库历史与SSI&lt;/strong&gt;。
我发现国内有很多技术博客对事物的描述不太准确，会对初学者造成很多疑惑，还有很多小伙伴对事物历史和pg中的SSI不是很熟悉。这次我从wiki、SQL官方标准和各种论文中收集和汇总了事务的准确含义、事务的历史和SSI的理论基础。分享内容的主要思路是从事务的历史推进到一些92标准中不存在的异象，再到消灭这些异象可以怎么做，再循序渐进到pg库的SSI是怎么做的。
全篇分享分为4个部分：事务的基础、事务的历史、SSI理论知识、PostgresSQL中的SSI。&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%9f%ba%e7%a1%80" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;在了解事务历史和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%bb%80%e4%b9%88%e6%98%af%e4%ba%8b%e5%8a%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;事务的原本含义&lt;/strong&gt;：事务=&amp;gt;transaction=&amp;gt;交易。交易是事务原本的含义，而我们数据库中的事务就是从交易这个词汇而来。
&lt;strong&gt;数据库中的事务&lt;/strong&gt;：&lt;em&gt;事务是关系型数据库的基本工作单元&lt;/em&gt;。比如
从A表删除数据，从B表插入数据，我们可以把他们这两个动作包装成一个事务，他俩必须都完成。但是也有可能因为某些意外因素，事务执行到一半失败或者取消了，此时只能整个事务中的所有操作全部回退，回到事务前的状态，A也不执行删除，B也不执行插入&lt;/p&gt;

&lt;h3 class="relative group"&gt;ACID
 &lt;div id="acid" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#acid" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;ACID是数据库事务的重要特性。它决定了交易事务是否是可靠的、可信任的。



&lt;img src="https://lastdba.com/img/csdn/cc73d604121e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;原子性**：事务中的各个操作要么全部完成，要么全部取消。
就像化学中的原子一样不可分割、不可分裂。如果一个事务执行到一半有问题执行失败了，执行不下去了，那么这个事务必须全部回退。
&lt;strong&gt;一致性&lt;/strong&gt;：事务完成时，所有数据都保持一致状态。
这个定义其实比较模糊。事务一般会操作数据，数据库中数据的状态会被更新，因为事务操作，数据会从一个状态到另一个状态，这个状态必须是合理合法的，数据逻辑必须和真实世界的逻辑一致。这里可能比较抽象，打个比方：比如说甲有100元，乙有200元，他们合起来的钱是300元，这时乙向甲转账100元，那么甲就有200元，乙有100元，他们合起来的钱仍然是300元。重点：&lt;em&gt;这个虚拟世界的数据变化应该与真实世界的逻辑保持一致&lt;/em&gt;。
&lt;strong&gt;隔离性&lt;/strong&gt;：多个事务并发执行的结果必须和分开单独执行的结果一致。
比如2个事务，一个接着一个的串行执行，必须和并行执行结果一致。（这个是wiki的官方理解，也是SQL标准中的定义，请记住这个定义，这个是本篇的重点）
&lt;strong&gt;持久性&lt;/strong&gt;：事务处理结束后，对数据的修改就是永久的。
如果更新后数据放入内存中，关机就没了，那么他理应放入磁盘里，那么放入磁盘是安全的吗？如果磁盘损坏了呢？我们可以有高可用架构写多份数据，再延伸一下还可以有地域级别的容灾，那如果我们再杠一下，多个地域都挂了呢？如果从架构上来介绍，这个问题好像没有答案。但是从&lt;em&gt;用户的角度&lt;/em&gt;来看，其实比较容易理解。比如用户在存钱的时候，他把钞票放进去了，那么账户上应该显示他存入的钱的数字，这个数字对于用户来说是永久的，用户认为即使天塌下来，他的账户里都应该有这个数字，这是持久性的含义。&lt;/p&gt;

&lt;h3 class="relative group"&gt;ANSI-SQL92标准
 &lt;div id="ansi-sql92标准" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansi-sql92%e6%a0%87%e5%87%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/41ff840d82af.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;1992年美国国家标准ANSI SQL-92标准中定义了4种隔离级别和3种异常现象。
虽然现在的数据库行业基本都参照ISO国际标准了。



&lt;img src="https://lastdba.com/img/csdn/32fd2f2e70e0.png" alt="在这里插入图片描述" /&gt;
但这个92年的美国标准对数据库行业影响非常大，相信很多玩数据库小伙伴的都知道4种隔离级别。&lt;/p&gt;

&lt;h3 class="relative group"&gt;92标准的隔离级别
 &lt;div id="92标准的隔离级别" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#92%e6%a0%87%e5%87%86%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;ANSI SQL-92标准定义了4种隔离级别



&lt;img src="https://lastdba.com/img/csdn/7b6b2fd5d336.png" alt="在这里插入图片描述" /&gt;
事务的隔离级别从高到低。注意看可串行化：系统中所有的事务并行执行时和串行化执行时的结果没有差别，事务之间互不影响
。这个是不是跟ACID的隔离性定义有点像？
4种隔离级别都可以满足事务全做或全部不做，只是在隔离性上有不同的定义，所有的隔离级别都可有原子性、一致性、持久性，但不同的隔离级别有不同的隔离性，&lt;strong&gt;从定义上看，其实只有可串行化是完全满足ACID的&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 class="relative group"&gt;92标准的异常现象
 &lt;div id="92标准的异常现象" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#92%e6%a0%87%e5%87%86%e7%9a%84%e5%bc%82%e5%b8%b8%e7%8e%b0%e8%b1%a1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;92标准中定义了3种异常现象，网上有很多相关的定义，其实很多说的都不太准确，我们这里直接从&lt;em&gt;92标准文档&lt;/em&gt;中摘取出来3种异常现象的定义&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/80b283e33a76.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;脏读&lt;/strong&gt;：事务T1更新了一行，事务T2可以在事务T1提交前读到这个行。如果T1执行了回退，T2会读到一个从未提交的行。
*脏读有个明显的问题，用户可能不知道钱是不是到账了，在事务没有完成前用户就可以查到账户里有钱已经转入了，但是某些原因失败了导致事务回退，钱又没了，这对用户来说是难以理解的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不可重复读&lt;/strong&gt;：事务T1读取了一行，事务T2更新或删除了这行并提交了。如果T1再次读取这行，它会发现行被更改或删除了。
&lt;strong&gt;幻读&lt;/strong&gt;：事务T1通过某些条件读取到了N行，事务T2执行sql生成了行并满足了这个条件，T1重复读取时发现了不一致的行结果。
*不可重复读和幻读的区别在于一是其他事务的更新或删除导致同一事务内读数不一致，一个是其他事务的插入导致同一事物内读数不一致&lt;/p&gt;

&lt;h3 class="relative group"&gt;92标准与pg
 &lt;div id="92标准与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="#92%e6%a0%87%e5%87%86%e4%b8%8epg" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/2784c3889598.png" alt="在这里插入图片描述" /&gt;
在92标准的隔离级别和异常现象是呈阶梯式的，除了可串行化没有异常现象外，每个隔离级别都有阶梯式的增加了异常现象。然后我们看下面这个表格，这是pgsql中的隔离级别和异常现象，他跟92标准是&lt;strong&gt;不一样&lt;/strong&gt;的。&lt;/p&gt;

&lt;h3 class="relative group"&gt;为什么PostgreSQL数据库隔离级别与“92标准”不一致的情况呢？
 &lt;div id="为什么postgresql数据库隔离级别与92标准不一致的情况呢" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%88postgresql%e6%95%b0%e6%8d%ae%e5%ba%93%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e4%b8%8e92%e6%a0%87%e5%87%86%e4%b8%8d%e4%b8%80%e8%87%b4%e7%9a%84%e6%83%85%e5%86%b5%e5%91%a2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;为什么未提交读与“92标准”不一致？未提交读实在是太奇怪了，在关系型数据库中基本想不到使用未提交读的场景。它严重违反了事务的隔离性。PostgreSQL将“未提交读”视为“已提交读”&lt;/li&gt;
&lt;li&gt;为什么可重复读与“92标准”不一致？PostgreSQL通过快照实现MVCC多版本并发控制， PostgreSQL中的可重复读级别实际上是快照隔离级别，这个隔离级别实际上没有幻读这个异常现象&lt;/li&gt;
&lt;li&gt;虽然“92标准”影响深远，但是还是有许多数据库没有全部实现它。&lt;/li&gt;
&lt;li&gt;ANSI SQL-92标准定义模糊。“92标准”在数据库行业很有代表性，&lt;em&gt;“它很好，但不够好”&lt;/em&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="#%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%8e%86%e5%8f%b2" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;事务的历史
 &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="#%e4%ba%8b%e5%8a%a1%e7%9a%84%e5%8e%86%e5%8f%b2-1" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;理解 &lt;em&gt;“它很好，但不够好”&lt;/em&gt;，需要把回顾一下事务的历史，时间往回推40年。



&lt;img src="https://lastdba.com/img/csdn/9510b3d76415.png" alt="在这里插入图片描述" /&gt;
注意92标准提出的时间和“92批判”的时间。虽然92标准很“烂”，但是仍然对数据库行业影响深远。随后在很多串行化理论得到证实后，PostgresSQL数据库第一个在商业数据库中实现了SSI。&lt;/p&gt;

&lt;h3 class="relative group"&gt;对92标准的批判
 &lt;div id="对92标准的批判" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%af%b992%e6%a0%87%e5%87%86%e7%9a%84%e6%89%b9%e5%88%a4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;在92标准出来不久，一些微软工程师和学者对92标准做了批评，并在提出了更多的隔离级别和异常现象。
之前92标准中定义了4个隔离级别和3个异常现象，在“对92的批评”中有6种隔离级别和8种异常现象。



&lt;img src="https://lastdba.com/img/csdn/9e1cc8e57c9e.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更多的隔离级别和异常现象出现， 它们没有在ANSI SQL-92中定义&lt;/li&gt;
&lt;li&gt;快照隔离在可重复读和可串行化间。这也是为什么pgsql的可重复读跟可串行化这么像的原因之一&lt;/li&gt;
&lt;li&gt;写偏序异常提出。它会在快照隔离级别发生。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class="relative group"&gt;热门数据库的隔离级别


&lt;img src="https://lastdba.com/img/csdn/de1258812b3c.png" alt="在这里插入图片描述" /&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%83%ad%e9%97%a8%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e5%9c%a8%e8%bf%99%e9%87%8c%e6%8f%92%e5%85%a5%e5%9b%be%e7%89%87%e6%8f%8f%e8%bf%b0" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;mysql在serializability隔离级别下，读对数据加读共享锁，读会阻塞写&lt;/li&gt;
&lt;li&gt;oracle其实也可以设置serializability隔离级别，并号称是支持可串行化的，但是它不是真正的可串行化，只是snapshot isolation&lt;/li&gt;
&lt;li&gt;PostgreSQL支持serializability，它在snapshot isolation基础上实现可串行化，全称为可串行化快照隔离Serializable Snapshot Isolation (SSI) ，读写不会相互阻塞&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;能看出来3者的差别，只有pgsql的可串行化是有干货的。&lt;/p&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="#%e4%b8%ba%e4%bb%80%e4%b9%88oracle%e6%ac%ba%e9%aa%97%e4%ba%86%e6%88%91%e4%bb%ac" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;oracle欺骗了我们什么呢？他把&lt;em&gt;快照隔离&lt;/em&gt;这个隔离级别当成&lt;em&gt;可串行化&lt;/em&gt;隔离级别糊弄我们。
为什么会发生这种情况呢？
如果我们把snapshot isolation加到ANSI SQL-92标准中



&lt;img src="https://lastdba.com/img/csdn/88c0c04ad181.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“92标准”的异象定义较少，也没有定义快照隔离，以92标准来看，snapshot isolation看上去跟serializable差不多&lt;/li&gt;
&lt;li&gt;大部分关系型数据库都以“92标准”为标准，包括oracle。但是随后更好的标准出现后，他们没有做出改变&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%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;ol&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;高级别的隔离会丢失一些性能。大量的改造工作可能是吃力不讨好的，应用需要在“高并发”和“无异常现象”间做抉择；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;业务基于机制开发，而不是规则开发。业务多少有点适应弱隔离级别的异常现象，特别是RC 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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%e6%9c%89%e4%bb%80%e4%b9%88%e6%84%8f%e4%b9%89" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;如果弱隔离在真实世界都好像没问题，那么可串行化还有什么意义呢？其实是有的&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;虽然应用适应了弱隔离级别，但是不代表他们真的理解了&lt;/li&gt;
&lt;li&gt;使用可串行化，应用可以极大的减少对数据异常的担忧&lt;/li&gt;
&lt;li&gt;除了可串行化外，其他的隔离级别都有各自的异常现象，他们也不完全满足ACID的隔离性&lt;/li&gt;
&lt;li&gt;可串行化可以消灭异常现象这个“蛀虫”，完全保证数据的安全性&lt;/li&gt;
&lt;li&gt;可串行化在理论上已经证明可以实现&lt;/li&gt;
&lt;li&gt;一些可串行的实现确实极大的降低了并发性，但是还有其他的可串行化实现，对并发性影响很小。比如说，可串行化快照隔离SSI可串行化的实现&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;SSI理论知识
 &lt;div id="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="#ssi%e7%90%86%e8%ae%ba%e7%9f%a5%e8%af%86" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;说了那么多事务的基本知识和事务的历史，终于来到了SSI的概念。但在了解SSI之前，还得先了解2个概念：可串行化、快照隔离&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;img src="https://lastdba.com/img/csdn/71f922c0363f.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可串行化的含义&lt;/strong&gt;
如果每个事务本身是正确的，即满足某些完整性条件，那么包括这些事务的任何串行执行的时间表是正确的（其事务仍然满足其条件）：“串行”意味着事务在时间上不重叠，并且不能相互干扰，即彼此之间存在完全隔离。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可串行化的实现&lt;/strong&gt;
事务发展早期，可串行化（serializable）通过严格两阶段锁（SS2PL）实现，读写相互阻塞，直到事务结束。消除了异常现象但SS2PL丢失了高性能。
除了SS2PL实现可串行化，还有其他方式，比如可串行化快照隔离（SSI）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可串行化的意义&lt;/strong&gt;
为了保证没有异常，可串行化会丢失一些并发性（不同实现方式有所不同），但可以真正保证数据的ACID隔离性。也就是说没有实现串行化的数据库，其实没有完全支持ACID特性。
可串行化在理论上已经证明可以实现，但是真实的数据库世界有点”不正常“。实际上，可串行化是事务隔离级别中最高级的，也是学者和业界大佬强力推荐的隔离级别，不过绝大部分数据库在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;&lt;strong&gt;快照隔离的定义&lt;/strong&gt;
在快照隔离下执行的事务是在事务开始时拍摄的数据库快照上操作的。当事务结束时，只有当事务更新的值自快照拍摄以来没有外部更改时，它才会成功提交。
快照隔离级别顾名思义就是就是使用了快照，这广泛用于实现MVCC，使多版本并发机制支持用户并发执行事务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;快照隔离的出现&lt;/strong&gt;
ANSI SQL92并未定义快照隔离snapshot isolation(SI)，这个隔离级别随着数据库行业发展才出现。1992年 ANSI SQL92标准基于数据库的锁而定义，所以没有快照隔离级别这个定义。直到1995年《批判》的出现才被提出。&lt;/p&gt;

&lt;h3 class="relative group"&gt;SSI
 &lt;div id="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="#ssi" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/8142817784c7.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可串行化快照隔离SSI&lt;/strong&gt;
由于快照隔离的广泛应用，而可串行化是学术上数据库需要达到的隔离级别目标。可串行化快照隔离Serializable Snapshot Isolation (SSI) 顾名思义，在快照隔离的基础上实现可串行化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么有SSI？&lt;/strong&gt;
由于ANSI92标准的模糊性，虽然没有定义快照隔离，但许多数据库实际上就是使用的快照隔离。而快照隔离同样存在一些异常现象（包括写偏序），SSI的出现就是为了解决这些异常现象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSI相对于S2PL的优势&lt;/strong&gt;
传统的可串行化通过S2PL实现，在S2PL下写操作会阻塞其他事务读写，虽然可以实现可串行化，不会有写偏序异常等问题，但会产生很多锁冲突，降低并发性能。而通过快照实现的MVCC读写互不阻塞，只有写写冲突。在此基础上实现的SSI对并发性的影响相比传统S2PL要小很多。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PG实现SSI&lt;/strong&gt;
SSI在pg9.1开始实现SSI，是第一个实现SSI的商业数据库。&lt;/p&gt;

&lt;h3 class="relative group"&gt;3种依赖关系
 &lt;div id="3种依赖关系" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3%e7%a7%8d%e4%be%9d%e8%b5%96%e5%85%b3%e7%b3%bb" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/bd6547d3dd94.png" alt="在这里插入图片描述" /&gt;
**读写依赖：**事务T1写数据项的一个版本，事务T2读这个版本，意味着T1先于T2
**写写依赖：**事务T1写数据项的一个版本，事务T2使用一个新版本替换了这个版本，意味着T1先于T2
**读写反依赖：**事务T1写数据项的一个版本，事务T2读这个版本之前的版本，意味着T2先于T1&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%e7%9a%84%e7%90%86%e8%ae%ba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;由于某些冲突构成环，会出现串行化异常。也就是说，有些并行执行的事务，从理论上就是不可串行化的。其中比较容易理解的一个就是写偏序(write skew)。
写偏序只发生在rw模型，ww、wr均不会发生写偏序，并且事务必须在并发条件下才会出现。&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/30043eef5317.png" alt="在这里插入图片描述" /&gt;
简单写偏序：事务T1读写反依赖T2，T2又读写反依赖T1。这两个事务的并发执行是不可串行化的。&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%90%91%e7%9a%84%e7%8e%b0%e5%ae%9e%e9%97%ae%e9%a2%98" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;有许多现实案例可以出现写偏序异常，我们用一个经典的黑白球问题来理解写偏序



&lt;img src="https://lastdba.com/img/csdn/4dada0644aac.png" alt="在这里插入图片描述" /&gt;
袋中有4个球，2个白球和2个黑球。此时有两个事务，P和Q。P将所有黑球改成白球，Q将所有白球改成黑球。此时可以有两个串行执行，&amp;lt;P，Q&amp;gt;或&amp;lt;Q，P&amp;gt;。在这两种情况下，最终结果是袋中有4个白球或者4个黑球。
&lt;strong&gt;但是&lt;/strong&gt;，快照隔离允许另一种结果：
事务 P 拿出2个黑球
事务 Q 拿出2个白球
事务 P 将手中所有黑球改成白球，放回袋中
事务 Q 将手中所有白球改成黑球，放回袋中
此时袋中还是2个黑球和2个白球。这在任何一个串行执行中都是不可能的。
但这在快照隔离中是有效：每个事务都维护数据库的一致视图，并且其写集不与任何并发事务的写集重叠，如此白球黑球发生交换。&lt;/p&gt;
&lt;p&gt;我们还可以把问题具象化、更实际。举一个比较粗糙的例子：比如我手里有几个银行卡，一半冻结，一半解冻状态。我在一个终端上执行了所有卡冻结，然后在另一个终端上立即执行所有卡解冻。这个时候从目的上讲，我的卡应该是全部解冻的，但是出现了一个奇怪的现象，以前冻结的卡解冻了，以前解冻的卡冻结了。作为一个客户，我会感到困惑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;黑白球问题说明&lt;/strong&gt;：快照隔离执行结果与串行化执行结果不一致，快照隔离下发生写偏序异常，数据结果与预期不一致。&lt;/p&gt;

&lt;h2 class="relative group"&gt;PostgreSQL中的SSI
 &lt;div id="postgresql中的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="#postgresql%e4%b8%ad%e7%9a%84ssi" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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%e6%98%af%e6%80%8e%e4%b9%88%e5%a4%84%e7%90%86ssi%e7%9a%84" 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;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;set default_transaction_isolation = &amp;lsquo;serializable&amp;rsquo;;&lt;/td&gt;
 &lt;td&gt;set default_transaction_isolation = &amp;lsquo;serializable&amp;rsquo;;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;begin; update dots set color = &amp;lsquo;black&amp;rsquo; where color = &amp;lsquo;white&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; 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&gt;commit;&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;&lt;/td&gt;
 &lt;td&gt;&lt;code&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;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;事务1把所有白色改成黑色，事务2把所有黑色改成白色，然后2个事务提交。第一个提交的事务成功了，第二个提交的事务失败了，这里是报错，说的是：&lt;em&gt;因为读写依赖不可串行化，把当前事务作为支点取消了，如果重新尝试事务，可能会成功&lt;/em&gt;。
这里当然会成功，另一个事务已经完成，一个事务不会构成依赖关系，不会构成环。在其他隔离级别，比如可重复读、已提交读，这个两个事务这样执行不会有任何报错，正常执行，但是数据执行结果跟SSI的执行结果不同。&lt;/p&gt;

&lt;h3 class="relative group"&gt;PostgreSQL对SSI实现的优化
 &lt;div id="postgresql对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="#postgresql%e5%af%b9ssi%e5%ae%9e%e7%8e%b0%e7%9a%84%e4%bc%98%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;postgresql在快照隔离级别基础上实现了可串行化SSI，并对其做了很多优化，以提高高隔离级别下的并发性，pgsql对ssi的优化主要有3点：
&lt;strong&gt;安全快照&lt;/strong&gt;：不会引起环形结构的只读事务，不必检测冲突，可减少检查负担和内存负担&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;延迟事务&lt;/strong&gt;：延迟事务可重新尝试。在检查到”危险结构“后，延迟事务会被取消，然后再次尝试执行。延迟事务需要显示声明&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;检测粒度升级&lt;/strong&gt;：多个细粒度的锁可合成粗粒度的锁减少内存开销&lt;/p&gt;
&lt;p&gt;优化结果：
优化结果-压测性能对比：



&lt;img src="https://lastdba.com/img/csdn/5bba1b13a844.png" alt="在这里插入图片描述" /&gt;
绿色线是快照隔离基准线，蓝色线pgsql的SSI性能跟快照隔离已经很接近了。而褐色的线是SSI在没有只读事务，全是数据更改事务的场景，能看出只读事务优化对性能提升也很大。实际上一般业务系统，只读事务都会比更改事务多。红色的线是严格两阶段提交实现的可串行化，性能惨不忍睹。
下面这个表格，是并发压力和事务失败率，因为有些事务需要取消才能打破环，所以可串行化肯定比弱隔离取消的事务更多，这个表格也能看出pgsql的SSI的并发度和事务成功率远高于严格两阶段提交。&lt;/p&gt;
&lt;p&gt;优化结果-请求量和失败率：



&lt;img src="https://lastdba.com/img/csdn/fe74c76c6333.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="#%e6%80%bb%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可串行化能简化系统开发的问题，开发人员不需要管并发下事务的异常现象，特别是如今更多的高并发系统下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PostgreSQL的可串行化显然比严格两阶段提交模式更好。不仅性能更好，而且中止事务的概率也更低。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PostgreSQL是第一个实现SSI的商业数据库，而很多传统关系型数据库根本不支持可串行化，pgsql数据库往前走了一大步。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PostgreSQL不仅实现了SSI，还在此基础上做了很多优化，比如只读事务和内存优化，并且效果显著&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>我的年终总结2023</title><link>https://lastdba.com/2024/08/12/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932023/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%88%91%E7%9A%84%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%932023/</guid><description>&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从2023年初开始，我就给自己定下了23年的主要任务——&lt;strong&gt;学习PostgreSQL数据库&lt;/strong&gt;。虽然没有定下细致的计划，但总体的目标是把PG的一些基础知识学完。后来发现我想简单了，学习PG的成本比我想象的多的多，导致23年这个目标没有完成。比如PG事务章节，我以为2周可以拿下，我大概学了2个月。无论怎样，坚持学习还是学到了一些东西：&lt;/p&gt;</description><content:encoded>
&lt;h2 class="relative group"&gt;As a DBA
 &lt;div id="as-a-dba" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#as-a-dba" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从2023年初开始，我就给自己定下了23年的主要任务——&lt;strong&gt;学习PostgreSQL数据库&lt;/strong&gt;。虽然没有定下细致的计划，但总体的目标是把PG的一些基础知识学完。后来发现我想简单了，学习PG的成本比我想象的多的多，导致23年这个目标没有完成。比如PG事务章节，我以为2周可以拿下，我大概学了2个月。无论怎样，坚持学习还是学到了一些东西：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/1783a492fc8a.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;其中优化器章节，其实是没有完成的，虽然我有罪但是我还是要解释。优化章节已经写了超过两个月了，不是我偷懒，而是根本写不完。已经写到触及typora的文字上限——8000字左右会卡，所以被动分P，已经分到第四P了：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/c2313549e7fe.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;即便是这样，优化章节应该一半都没有写到，只能厚着脸皮跨一年继续···个人感觉再来4个月，应该可以把优化章节完成···即便是这样，优先级还得往后稍稍，时间真的不够！&lt;/p&gt;

&lt;h2 class="relative group"&gt;READING
 &lt;div id="reading" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#reading" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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;我利用的碎片时间来阅读，只是写读后感需要花2-3个小时，没有占用太多学习时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PG本身的技术书肯定是看了一些的，不过我是针对性的看内容，比如优化部分我会把《PostgreSQL指南 内幕探索》《PostgreSQL技术内幕 查询优化深度探索》《PostgreSQL查询引擎源码技术解析》《数据库查询优化器的艺术》拿到一起看某个知识点，不注重看没看完，不是一本本的顺序看完的，所以这里的阅读书目就只列课外书。&lt;/p&gt;
&lt;p&gt;2023年的课外书书单（按喜好排名）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;《未来简史》&lt;/li&gt;
&lt;li&gt;《三国演义》&lt;/li&gt;
&lt;li&gt;《太空漫游》系列，2001、2010、2060、3001&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;li&gt;《万智有灵》&lt;/li&gt;
&lt;li&gt;《杀死一只知更鸟》&lt;/li&gt;
&lt;li&gt;《穷爸爸富爸爸》&lt;/li&gt;
&lt;li&gt;《when breath becomes air》&lt;/li&gt;
&lt;li&gt;《变形记》《判决》《饥饿艺术家》等卡夫卡短篇小说&lt;/li&gt;
&lt;/ol&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="#%e5%8d%9a%e5%ae%a2%e5%92%8c%e5%85%ac%e4%bc%97%e5%8f%b7" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;个人发文章有两个途径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSDN博客：&lt;a href="https://liuzhilong.blog.csdn.net" target="_blank" rel="noreferrer"&gt;https://liuzhilong.blog.csdn.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;公众号:liuzhilong62&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于博客已经坚持写了很多年了，2023年的大变化就是主要写PostgreSQL方面的内容，并且提高技术深度。公众号是我今年才新开的坑，也是23年一大尝试。博客和公众号都可以做技术分享，但他们面向的用户还是有些区别的，博客可以作为一种技术积累，而公众号更像是技术资讯。圈内有很多大佬是每天一篇（甚至几篇）的模式，个人非常佩服。不过也有做精品文章而不在意每天要发东西的大佬。我个人还是比较喜欢后者，一次把某个领域的知识大致学完，比较有整体性和针对性。很多时候我都会把比较长的文章分P发公众号（太长了我自己都不爱看），博客上我是没有分P的，所以对某篇文章有兴趣的读者可以在CSDN上搜下我的文章，更易于阅读。&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;p&gt;


&lt;img src="https://lastdba.com/img/csdn/a5205d91518d.png" alt="img" /&gt;
实战、演讲这些途径可遇不可求的，将学习的东西输出文章分享，会大大提高知识点的理解能力。看完一篇文章，可能十分钟就结束了，但是要输出成文章，可能要花10倍不止的时间。&lt;/p&gt;
&lt;p&gt;今年还尝试了做纯翻译类的技术文章，虽然技术研究价值不高，但是还是有学习价值和传播价值的，看一遍和翻译一遍同样会有不一样的理解程度，就像上面说的：主动学习。不过现在有点纠结的是，以前看不懂的根据google机翻然后再自己再润色一遍，现在有gpt了，一整篇文章他翻出来我都不用动什么词句，主动学习价值严重流水，全给AI学习了···&lt;/p&gt;
&lt;p&gt;23年我的创作风格变化比较大，写的东西比较杂，什么都尝试过，当然也知道要做垂直领域的创作，不过还是忍不住搞些有的没的，甚至公众号的名字都没想好~。目前要写的东西比较明确的是：技术文章和课外书阅读感想，以技术文章为主，其他类型的文章应该不会再写了。至于后面还会不会调整也不知道，至少公众号还有调整空间，总之先这样，先发射再调整。&lt;/p&gt;
&lt;p&gt;23年的博客数据不太好统计了，只能给个2017年到2023年的博客数据，打个snapshot。&lt;/p&gt;
&lt;p&gt;CSDN blog：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/d6b07e98d21d.png" alt="在这里插入图片描述" /&gt;&lt;/p&gt;
&lt;p&gt;公众号followers：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/csdn/dd005d674681.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="#%e6%9c%80%e5%90%8e" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;2023年最大的感悟——时间。时间真的不够！&lt;/p&gt;
&lt;p&gt;23年6月17日的时候参加PostgreSQL数据库技术峰会成都站的分享，把刚练成的热乎的PostgreSQL事务方面知识给大佬们分享，第一次上台相当紧张，这里还要感谢一下灿总给的机会。这次分享有个小插曲，可见23年的时间对我来说是多么局促。我另外还有个非全研究生的学习，分享当天就是我期末考试的时间，讲完我就直奔机场···最后还是缺考3门只有等重修···太难了&lt;/p&gt;
&lt;p&gt;什么work-life balance已经全面放弃了，能有个work-learning balance就不错。每天下班不是想休息而是想回家看书，最后还是有很多东西没有完成，留给了2024年的我。&lt;/p&gt;
&lt;p&gt;对2024年的期望：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;把论文完成，顺利毕业&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;把PG优化部分完成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再说&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>我要查的表没有在执行计划中</title><link>https://lastdba.com/2024/08/12/%E6%88%91%E8%A6%81%E6%9F%A5%E7%9A%84%E8%A1%A8%E6%B2%A1%E6%9C%89%E5%9C%A8%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E4%B8%AD/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E6%88%91%E8%A6%81%E6%9F%A5%E7%9A%84%E8%A1%A8%E6%B2%A1%E6%9C%89%E5%9C%A8%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E4%B8%AD/</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%e6%9f%a5%e7%9a%84%e8%a1%a8%e6%b2%a1%e6%9c%89%e5%9c%a8%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e4%b8%ad" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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:#66d9ef"&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;*&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column1 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column1&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;--中间省略很多A字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column99 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column99&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &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;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a AA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;inner&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; table_b BB &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; AA.lzl_key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BB.lzl_id
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AA.column_code &lt;span style="color:#f92672"&gt;=&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;GROUP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) B &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; B.lzl_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A.lzl_key
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.flagflagflag &lt;span style="color:#f92672"&gt;=&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;AND&lt;/span&gt; A.typetypetype &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) TEMP
&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;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1000&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;</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%e6%9f%a5%e7%9a%84%e8%a1%a8%e6%b2%a1%e6%9c%89%e5%9c%a8%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92%e4%b8%ad" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&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:#66d9ef"&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;*&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column1 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column1&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;--中间省略很多A字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column99 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column99&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &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;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a AA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;inner&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; table_b BB &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; AA.lzl_key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BB.lzl_id
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AA.column_code &lt;span style="color:#f92672"&gt;=&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;GROUP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) B &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; B.lzl_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A.lzl_key
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.flagflagflag &lt;span style="color:#f92672"&gt;=&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;AND&lt;/span&gt; A.typetypetype &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) TEMP
&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;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1000&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; 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;2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;68&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;1105&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;038&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;039&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;0&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; Buffers: shared hit&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:#f92672"&gt;-&amp;gt;&lt;/span&gt; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_a a (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1105&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;036&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;037&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;0&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: (((flagflagflag)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((typetypetype)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2&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:#66d9ef"&gt;Rows&lt;/span&gt; Removed &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; Filter: &lt;span style="color:#ae81ff"&gt;38&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;184&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;066&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;可以看到，sql本身是比较复杂的，SQL的逻辑查了3次表，总共查了2张表。table_a 在执行计划中我可以理解，但是需要查的table_b根本没在执行计划里面！这个执行计划只不过是简单的全表扫描了table_a。&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%e6%9e%90%e7%9a%84%e5%bf%83%e8%b7%af%e5%8e%86%e7%a8%8b" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;中间其实想过很多可能，不过最有可能的是逻辑优化了，也就是说pg优化器认为table_b不需要查。
观察sql发现sql最终只查询了table_a的字段，没有查table_b。此时任意增加一个中间表B的字段，sql执行计划看上去就“正常”了，访问了table_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;&lt;span style="color:#66d9ef"&gt;explain&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 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;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column1 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column1&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;--中间省略很多A字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.column99 &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;column99&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; B.lzl_id &lt;span style="color:#75715e"&gt;--新增一个B中间表的字段
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &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;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_a AA
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;inner&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; table_b BB &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; AA.lzl_key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BB.lzl_id
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AA.column_code &lt;span style="color:#f92672"&gt;=&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;GROUP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lzl_id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) B &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; B.lzl_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; A.lzl_key
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A.flagflagflag &lt;span style="color:#f92672"&gt;=&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;AND&lt;/span&gt; A.typetypetype &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) TEMP
&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;
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;offset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1000&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;Limit&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;69&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;67&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;1113&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; Nested Loop &lt;span style="color:#66d9ef"&gt;Left&lt;/span&gt; &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;11&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;72&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;14&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;1113&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; Filter: (bb.lzl_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a.lzl_key)
&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; table_a a (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;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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1113&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Filter: (((flagflagflag)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;::text) &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; ((typetypetype)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2&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; &lt;span style="color:#66d9ef"&gt;Group&lt;/span&gt; (cost&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;72&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;74&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;5&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:#66d9ef"&gt;Group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: bb.lzl_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; Sort (cost&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;72&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;73&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;5&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; Sort &lt;span style="color:#66d9ef"&gt;Key&lt;/span&gt;: bb.lzl_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; Nested Loop (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;15&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;11&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;5&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; table_a aa (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;70&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; Filter: ((company_code)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&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; &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_table_b_lzl_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_b bb (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;15&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;8&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;13&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: (lzl_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; aa.lzl_key)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这看上去跟left join有关系，但是简单想想又不对，因为右表的结果是会影响查询的最终结果的，不应该不去查右表。随便来个简单的left 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:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; lzlright &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;lzlright.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;Left&lt;/span&gt; &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;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;04&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;15&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;320&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; Hash Cond: (lzlleft.a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; lzlright.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; lzlleft (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;13&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;320&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; Hash (cost&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;02&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;02&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;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; Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlright (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;1&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;02&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;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;但是，在中间表B中，有个关键字&lt;code&gt;GROUP BY&lt;/code&gt;。如果把&lt;code&gt;GROUP BY&lt;/code&gt;去掉，那么无论有没有查询B的字段，都会访问table_b。
我们再在测试表中加个group 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:#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; lzlleft;
&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; zzz
&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;Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;259&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; lzlright;
&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; qwer
&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; poiuy 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: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; lzlright.b &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &lt;span style="color:#66d9ef"&gt;full&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; lzlright &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;lzlright.b &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; lzlright.b;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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:#66d9ef"&gt;null&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; poiuy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; qwer
&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;这里就意识到了group by出来的结果集一定有一个特性——&lt;strong&gt;唯一性&lt;/strong&gt;。
我们再在测表里加group 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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; a) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.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;Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft (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;13&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;320&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;右表不查了！
根据右表唯一性的原则，下面还可以有一些骚操作：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--distinct确保右表唯一
&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; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;distinct&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.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;Seq Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft (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;13&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 style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;320&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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--唯一索引确保右表唯一，哪怕是select a from lzlright
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; explain select lzlleft.a from lzlleft left join (select a from lzlright) c on lzlleft.a=c.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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hash Left Join (cost=17.20..49.12 rows=512 width=4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash Cond: (lzlleft.a = lzlright.a)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Seq Scan on lzlleft (cost=0.00..13.20 rows=320 width=4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Hash (cost=13.20..13.20 rows=320 width=4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; Seq Scan on lzlright (cost=0.00..13.20 rows=320 width=4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(5 rows)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: 0.510 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; create unique index idx_right on lzlright(a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CREATE INDEX
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: 3.576 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; explain select lzlleft.a from lzlleft left join (select a from lzlright) c on lzlleft.a=c.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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Seq Scan on lzlleft (cost=0.00..13.20 rows=320 width=4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(1 row)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;到这里来个分析小结：只要右表的数据是唯一的且只查询左表数据时，不需要真的去访问右表 。所以这不是一个bug，而是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="#%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;本期没有源码分析~
优化器源码实在太难了，这里就找了下优化器源码的注释看了下。可以搜索关键字&lt;code&gt;unique-ify&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:#f92672"&gt;*&lt;/span&gt; Also, this routine and others in this module accept the special JoinTypes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; JOIN_UNIQUE_OUTER and JOIN_UNIQUE_INNER to indicate that we should
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; unique&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ify the outer or inner relation and then apply a regular inner
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; join. These values are not allowed to propagate outside this module,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; however. Path cost estimation code may need to recognize that it&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; dealing with such a &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#f92672"&gt;---&lt;/span&gt; the combination of nominal jointype INNER
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; with sjinfo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;jointype &lt;span style="color:#f92672"&gt;==&lt;/span&gt; JOIN_SEMI indicates that. 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;特殊的JoinTypes：JOIN_UNIQUE_INNER 和JOIN_UNIQUE_OUTER ，尝试把外表和内表连接唯一化后，成为inner join。Path代价估算需要考虑这种场景。&lt;/p&gt;

&lt;h2 class="relative group"&gt;与oracle、mysql优化器的对比
 &lt;div id="与oraclemysql优化器的对比" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -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%8eoraclemysql%e4%bc%98%e5%8c%96%e5%99%a8%e7%9a%84%e5%af%b9%e6%af%94" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;对比看下oracle、mysql优化器有没有类似的逻辑优化提升&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--oracle
&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; lzlleft(a number);
&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; lzlright(a number);
&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; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;distinct&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.a;&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;--group by 唯一性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; a) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&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;no&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; selected
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Execution 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;Plan hash value: &lt;span style="color:#ae81ff"&gt;3533354041&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;|&lt;/span&gt; Id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Operation&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;Rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Bytes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Cost (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;CPU)&lt;span style="color:#f92672"&gt;|&lt;/span&gt; Time &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:#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:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;STATEMENT&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;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26&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:#ae81ff"&gt;20&lt;/span&gt;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OUTER&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;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26&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:#ae81ff"&gt;20&lt;/span&gt;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;2&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;ACCESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FULL&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LZLLEFT &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;13&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;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VIEW&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;1&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; (&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;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&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:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH &lt;span style="color:#66d9ef"&gt;GROUP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BY&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;1&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; (&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;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&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:#ae81ff"&gt;5&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;ACCESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FULL&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; LZLRIGHT &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;13&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;)&lt;span style="color:#f92672"&gt;|&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;01&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;Predicate Information (identified &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;operation&lt;/span&gt; id):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span 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; &lt;span style="color:#66d9ef"&gt;access&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;LZLLEFT&amp;#34;&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--ditinct 唯一 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;distinct&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&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;no&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; selected
&lt;/span&gt;&lt;/span&gt;&lt;span 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;Execution 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;Plan hash value: &lt;span style="color:#ae81ff"&gt;3859658234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;|&lt;/span&gt; Id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Operation&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;Rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Bytes &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Cost (&lt;span style="color:#f92672"&gt;%&lt;/span&gt;CPU)&lt;span style="color:#f92672"&gt;|&lt;/span&gt; Time &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:#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:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;STATEMENT&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;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26&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:#ae81ff"&gt;20&lt;/span&gt;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH &lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OUTER&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;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;26&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:#ae81ff"&gt;20&lt;/span&gt;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;2&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;ACCESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FULL&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; LZLLEFT &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;13&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;)&lt;span style="color:#f92672"&gt;|&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;01&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:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VIEW&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;1&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; (&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;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&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:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HASH &lt;span style="color:#66d9ef"&gt;UNIQUE&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;1&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:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; (&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;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;00&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;01&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:#ae81ff"&gt;5&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;ACCESS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FULL&lt;/span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; LZLRIGHT &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;13&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;)&lt;span style="color:#f92672"&gt;|&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;01&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;Predicate Information (identified &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;operation&lt;/span&gt; id):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span 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; &lt;span style="color:#66d9ef"&gt;access&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;LZLLEFT&amp;#34;&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;.&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&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;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;--mysql 
&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; lzlleft(a int &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;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;table&lt;/span&gt; lzlright(a int &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;/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;--group by唯一
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright &lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; a) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.a; 
&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:#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; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; select_type &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; partitions &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; possible_keys &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; key_len &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; filtered &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Extra &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:#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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlleft &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;index&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;PRIMARY&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:#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; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;derived2&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:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;auto_key0&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;&amp;lt;&lt;/span&gt;auto_key0&lt;span style="color:#f92672"&gt;&amp;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; lzldb.lzlleft.a &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; DERIVED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlright &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;index&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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:#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; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#75715e"&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;--distinct唯一
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; lzlleft.a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlleft &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;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;distinct&lt;/span&gt; a &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; lzlright) &lt;span style="color:#66d9ef"&gt;c&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; lzlleft.a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;c&lt;/span&gt;.a;
&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:#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; id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; select_type &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; partitions &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; possible_keys &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; key_len &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;rows&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; filtered &lt;span style="color:#f92672"&gt;|&lt;/span&gt; Extra &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:#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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlleft &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;index&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;PRIMARY&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:#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; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;derived2&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:#66d9ef"&gt;ref&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;auto_key0&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;&amp;lt;&lt;/span&gt;auto_key0&lt;span style="color:#f92672"&gt;&amp;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; lzldb.lzlleft.a &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;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; DERIVED &lt;span style="color:#f92672"&gt;|&lt;/span&gt; lzlright &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;index&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&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:#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; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;00&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; &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:#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;综上，oracle、mysql均不会对left join只查左表且右表唯一做优化，他们会访问右表。
pg优化器确实是有些东西的。&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><item><title>长事务、表膨胀、limit问题的一个经典案例</title><link>https://lastdba.com/2024/08/12/%E9%95%BF%E4%BA%8B%E5%8A%A1%E8%A1%A8%E8%86%A8%E8%83%80limit%E9%97%AE%E9%A2%98%E7%9A%84%E4%B8%80%E4%B8%AA%E7%BB%8F%E5%85%B8%E6%A1%88%E4%BE%8B/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://lastdba.com/2024/08/12/%E9%95%BF%E4%BA%8B%E5%8A%A1%E8%A1%A8%E8%86%A8%E8%83%80limit%E9%97%AE%E9%A2%98%E7%9A%84%E4%B8%80%E4%B8%AA%E7%BB%8F%E5%85%B8%E6%A1%88%E4%BE%8B/</guid><description>&lt;h1 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="#update%e4%b8%bb%e9%94%ae%e6%85%a2%e9%97%ae%e9%a2%98%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;一个简单的主键更新，update执行了超过1s，由于并发比较高，cpu直接打满&lt;/p&gt;</description><content:encoded>
&lt;h1 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="#update%e4%b8%bb%e9%94%ae%e6%85%a2%e9%97%ae%e9%a2%98%e5%88%86%e6%9e%90" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;一个简单的主键更新，update执行了超过1s，由于并发比较高，cpu直接打满&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2024&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;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;084&lt;/span&gt; CST,&lt;span style="color:#e6db74"&gt;&amp;#34;lzlopr&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lzl&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;158751&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;10.33.78.149:51502&amp;#34;&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;66055&lt;/span&gt;a6b.&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;c1f,&lt;span style="color:#ae81ff"&gt;172&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE&amp;#34;&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;03&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;19&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; CST,&lt;span style="color:#ae81ff"&gt;528&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19816630&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;970251337&lt;/span&gt;,LOG,&lt;span style="color:#ae81ff"&gt;00000&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;duration: 1218.688 ms plan:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Query Text: update table_a set (省略...）=$6 where column_id =$7
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Update on table_a (cost=0.40..5.49 rows=1 width=2774)
&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;gt; Index Scan using pk_id on table_a (cost=0.40..5.49 rows=1 width=2774)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; Index Cond: ((column_id)::text = $7)&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;PostgreSQL JDBC Driver&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;client backend&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;sql本身也非常简单，就是条件为=&amp;lsquo;主键&amp;rsquo;的更新。看update的执行计划，是走了pk主键索引的，所以从执行计划上看没有问题，问题不在执行计划突变。&lt;/p&gt;
&lt;p&gt;改写下sql（因为是update），&lt;code&gt;explain (analyze,buffers)&lt;/code&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:#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;,buffers) &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; table_a &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; column_id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d4f713370e584820a9b15e2218ea436a&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; Bitmap Heap Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_a (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;91&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;42&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;1156&lt;/span&gt;) (actual time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;052&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;354&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:#66d9ef"&gt;Recheck&lt;/span&gt; Cond: ((column_id)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;d4f713370e584820a9b15e2218ea436a&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Heap Blocks: exact&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; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;13870&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 &lt;span style="color:#66d9ef"&gt;Index&lt;/span&gt; Scan &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; pk_id (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;91&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;3&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;464&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;465&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;13866&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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((column_id)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;d4f713370e584820a9b15e2218ea436a&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4261&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;11&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;028&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;123&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;567&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;11&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;这里的真实执行计划没问题，但是shared hit=13870明显太高了。正常来说走主键不应该扫描太多的page，这里比较容易联想到表膨胀&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:#75715e"&gt;--表大小 \dt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Size&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;525&lt;/span&gt; MB&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;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;827&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_stat_all_tables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_live_tup &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;786&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_dead_tup &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;657604&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有只有800条活元组，但是有65w条死元组！主键扫描了多个page的原因应该就是这个，但是为啥没有回收死元组呢？
表在默认修改20%数据的时候就会触发autovacuum执行vacuum回收，这个在日志中可以看到，autovacuum是有被触发的：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2024-04-01 14:13:46.649 CST,,,14081,,660a5099.3701,1,,2024-04-01 14:13:45 CST,259/17828993,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic vacuum of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34;: index scans: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2024-04-01 14:13:47.801 CST,,,14081,,660a5099.3701,2,,2024-04-01 14:13:45 CST,259/17828994,971045014,LOG,00000,&amp;#34;&lt;/span&gt;automatic analyze of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; system usage: CPU: user: 0.08 s, system: 0.01 s, elapsed: 1.15 s&lt;span style="color:#e6db74"&gt;&amp;#34;,,,,,,,,,&amp;#34;&amp;#34;,&amp;#34;&lt;/span&gt;autovacuum worker&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;2024-04-01 14:14:46.673 CST,,,26136,,660a50d5.6618,1,,2024-04-01 14:14:45 CST,259/17829090,0,LOG,00000,&amp;#34;&lt;/span&gt;automatic vacuum of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;: index scans: &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;2024-04-01 14:14:47.833 CST,,,26136,,660a50d5.6618,2,,2024-04-01 14:14:45 CST,259/17829091,971049759,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic analyze of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34; system usage: CPU: user: 0.08 s, system: 0.03 s, elapsed: 1.15 s&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-01 14:15:46.680 CST,,,40743,,660a5111.9f27,1,,2024-04-01 14:15:45 CST,259/17829164,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic vacuum of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34;: index scans: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2024-04-01 14:15:47.849 CST,,,40743,,660a5111.9f27,2,,2024-04-01 14:15:45 CST,259/17829165,971055464,LOG,00000,&amp;#34;&lt;/span&gt;automatic analyze of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; system usage: CPU: user: 0.08 s, system: 0.03 s, elapsed: 1.16 s&lt;span style="color:#e6db74"&gt;&amp;#34;,,,,,,,,,&amp;#34;&amp;#34;,&amp;#34;&lt;/span&gt;autovacuum worker&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;2024-04-01 14:16:46.677 CST,,,52599,,660a514d.cd77,1,,2024-04-01 14:16:45 CST,259/17829263,0,LOG,00000,&amp;#34;&lt;/span&gt;automatic vacuum of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;: index scans: &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;2024-04-01 14:16:47.844 CST,,,52599,,660a514d.cd77,2,,2024-04-01 14:16:45 CST,259/17829264,971061382,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic analyze of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34; system usage: CPU: user: 0.08 s, system: 0.03 s, elapsed: 1.16 s&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024-04-01 14:17:46.699 CST,,,64858,,660a5189.fd5a,1,,2024-04-01 14:17:45 CST,234/16589539,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic vacuum of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34;: index scans: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2024-04-01 14:17:47.851 CST,,,64858,,660a5189.fd5a,2,,2024-04-01 14:17:45 CST,234/16589540,971066091,LOG,00000,&amp;#34;&lt;/span&gt;automatic analyze of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; system usage: CPU: user: 0.09 s, system: 0.02 s, elapsed: 1.15 s&lt;span style="color:#e6db74"&gt;&amp;#34;,,,,,,,,,&amp;#34;&amp;#34;,&amp;#34;&lt;/span&gt;autovacuum worker&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;2024-04-01 14:18:46.703 CST,,,78112,,660a51c5.13120,1,,2024-04-01 14:18:45 CST,259/17829409,0,LOG,00000,&amp;#34;&lt;/span&gt;automatic vacuum of table &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;lzl.public.table_a&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;: index scans: &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;2024-04-01 14:18:47.854 CST,,,78112,,660a51c5.13120,2,,2024-04-01 14:18:45 CST,259/17829410,971070390,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic analyze of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34; system usage: CPU: user: 0.09 s, system: 0.02 s, elapsed: 1.15 s&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&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;不仅有触发，而且间隔刚好是一分钟。autovacuum_naptime间隔触发时间默认就是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;&lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;show&lt;/span&gt; autovacuum_naptime ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; autovacuum_naptime 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#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:#66d9ef"&gt;min&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;p&gt;可以判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;autovacuum成功触发&lt;/li&gt;
&lt;li&gt;死元组可能回收不及，1分钟内产生的死元组大于20%（可能1分钟太长了）；或者根本没有回收，下次一定触发autovacuum&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看下autovacuum的具体内容：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;2024-04-01 10:22:44.648 CST,,,16827,,660a1a73.41bb,1,,2024-04-01 10:22:43 CST,170/16910186,0,LOG,00000,&lt;span style="color:#e6db74"&gt;&amp;#34;automatic vacuum of table &amp;#34;&amp;#34;lzl.public.table_a&amp;#34;&amp;#34;: index scans: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;pages: 0 removed, 48745 remain, 6 skipped due to pins, 0 skipped frozen
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;tuples: 0 removed, 744488 remain, 743666 are dead but not yet removable, oldest xmin: 969118077
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;buffer usage: 97603 hits, 0 misses, 5 dirtied
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;avg read rate: 0.000 MB/s, avg write rate: 0.028 MB/s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;system usage: CPU: user: 0.21 s, system: 0.22 s, elapsed: 1.41 s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WAL usage: 4 records, 3 full page images, 5129 bytes&amp;#34;&lt;/span&gt;,,,,,,,,,&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;autovacuum worker&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;autovacuum触发了，但是完全没有回收死元组&lt;code&gt;tuples: 0 removed, 744488 remain, 743666 are dead but not yet removable, oldest xmin: 969118077&lt;/code&gt;。&lt;code&gt;oldest xmin&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;select&lt;/span&gt; pid,usename,xact_start,state_change,wait_event,&lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;,query &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; pg_stat_activity &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;idle&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; xact_start ;
&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; usename &lt;span style="color:#f92672"&gt;|&lt;/span&gt; xact_start &lt;span style="color:#f92672"&gt;|&lt;/span&gt; state_change &lt;span style="color:#f92672"&gt;|&lt;/span&gt; wait_event &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;state&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 style="color:#ae81ff"&gt;164658&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; phbdspsqp &lt;span style="color:#f92672"&gt;|&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;04&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;36&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;275408&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;2024&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;01&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;08&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;299609&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; DataFileRead &lt;span style="color:#f92672"&gt;|&lt;/span&gt; active &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;minval&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;maxval&amp;#34;&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;min&lt;/span&gt;(ID) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; minval,&lt;span style="color:#66d9ef"&gt;max&lt;/span&gt;(TRACK&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;长事务就是这个早上8点多跑了几个小时sql。虽然不是一个表，但是因为是&lt;code&gt;oldest xmin&lt;/code&gt;所以也会有影响。
至此原因已经定位：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表A的update频繁，表膨胀风险较高&lt;/li&gt;
&lt;li&gt;表B长事务阻止表A死元组回收&lt;/li&gt;
&lt;li&gt;表A的update语句扫描了过多的page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结束长事务。&lt;code&gt;select pg_terminate_backend(164658)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;手动vacuum或者等待1分钟（以内）自动vacuum。 &lt;code&gt;vacuum table_a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_live_tup &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;707&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n_dead_tup &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;298&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;65w的死元组已清理。
再次查看执行计划：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;analyze&lt;/span&gt;,buffers) &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; table_a &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; column_id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d4f713370e584820a9b15e2218ea436a&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; Scan &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; pk_id &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_a (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;40&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;44&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;621&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;026&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:#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:#66d9ef"&gt;Index&lt;/span&gt; Cond: ((column_id)::text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;d4f713370e584820a9b15e2218ea436a&amp;#39;&lt;/span&gt;::text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Buffers: shared hit&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; Planning Time: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;057&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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;043&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;shared hit只有6，故障恢复。&lt;/p&gt;
&lt;p&gt;另外，vacuum只会回收死元组，但是不会清理空间，表还是那么大。这个只有等新数据复用空间或者repack等重建表的操作来回收&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;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;Size&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;525&lt;/span&gt; MB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 class="relative group"&gt;order by limit的番外sql优化：
 &lt;div id="order-by-limit的番外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="#order-by-limit%e7%9a%84%e7%95%aa%e5%a4%96sql%e4%bc%98%e5%8c%96" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&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:#66d9ef"&gt;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(ID) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; minval,&lt;span style="color:#66d9ef"&gt;max&lt;/span&gt;(ID) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; maxval &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; table_b &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; time_at &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; to_timestamp(&lt;span style="color:#e6db74"&gt;&amp;#39;2024-03-30 00:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;yyyy-MM-dd HH24:mi:ss&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;Result&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4298&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;4298&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;1&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;64&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; &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;0&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2149&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;32&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; pk_b &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_b (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;70&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1181490202&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;549896&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&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: ((ID)::text &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; Filter: (time_at &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; to_timestamp(&lt;span style="color:#e6db74"&gt;&amp;#39;2024-03-30 00:00:00&amp;#39;&lt;/span&gt;::text, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyy-MM-dd HH24:mi:ss&amp;#39;&lt;/span&gt;::text))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InitPlan &lt;span style="color:#ae81ff"&gt;2&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;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;Limit&lt;/span&gt; (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;70&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;2149&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;32&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;Backward&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; pk_b &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_b table_b_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;70&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1181490202&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;27&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;549896&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&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: ((ID)::text &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; Filter: (time_at &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; to_timestamp(&lt;span style="color:#e6db74"&gt;&amp;#39;2024-03-30 00:00:00&amp;#39;&lt;/span&gt;::text, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyy-MM-dd HH24:mi:ss&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;sql也很简单，条件只有一个时间字段 ，过滤性还可以
不过这个sql没有走 time_at 索引，而是走的 ID主键索引 。这个跟&lt;a href="https://blog.csdn.net/qq_40687433/article/details/134387782?spm=1001.2014.3001.5501" target="_blank" rel="noreferrer"&gt;limit问题&lt;/a&gt;是一样的。analyze是没有用的，最好是改写sql。
改写后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;explain&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;min&lt;/span&gt;(ID&lt;span style="color:#f92672"&gt;||&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; minval,&lt;span style="color:#66d9ef"&gt;max&lt;/span&gt;(ID&lt;span style="color:#f92672"&gt;||&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; maxval &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; table_b &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; time_at &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; to_timestamp(&lt;span style="color:#e6db74"&gt;&amp;#39;2024-03-30 00:00:00&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;yyyy-MM-dd HH24:mi:ss&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 style="color:#66d9ef"&gt;Aggregate&lt;/span&gt; (cost&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1201418&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;86&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1201418&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;87&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;64&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; idx_time_at &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; table_b (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;57&lt;/span&gt;..&lt;span style="color:#ae81ff"&gt;1195919&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;549896&lt;/span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;33&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: (time_at &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; to_timestamp(&lt;span style="color:#e6db74"&gt;&amp;#39;2024-03-30 00:00:00&amp;#39;&lt;/span&gt;::text, &lt;span style="color:#e6db74"&gt;&amp;#39;yyyy-MM-dd HH24:mi:ss&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;这个还不是执行计划突变，因为没有变。前几天同样是这样的执行计划，但是跑的比较快，原因是还是因为数据分布和limit的机制，数据很快就找到自然就返回了，这也是优化器为什么会选择主键索引；“运气不好”数据半天找不到就要跑很久。&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%b0%8f%e7%bb%93" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;一个经典的案例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;update频繁更新的小表&lt;/li&gt;
&lt;li&gt;长事务阻止死元组回收&lt;/li&gt;
&lt;li&gt;长事务是排序和limt操作（order by，max/min，group都有可能）导致的索引选择问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个故障，三个postgres的经典知识点，相当有代表性。&lt;/p&gt;</content:encoded></item><item><title>聊聊美剧202306</title><link>https://lastdba.com/2023/06/01/%E8%81%8A%E8%81%8A%E7%BE%8E%E5%89%A7202306/</link><pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate><guid>https://lastdba.com/2023/06/01/%E8%81%8A%E8%81%8A%E7%BE%8E%E5%89%A7202306/</guid><description>&lt;p&gt;​
刚把《黄石》系列看完，决定写点最近看的美剧，总共十一部，小评一下，写点东西~&lt;/p&gt;
&lt;p&gt;《黄石》&lt;/p&gt;
&lt;p&gt;《黄石》已经到第五季了，看样子还得继续拍。刚开始看《黄石》的时候，确实有种陷进去的感觉，很美很宏伟的电视剧，画面很棒风景很优美。而且还可以了解真实的老美是怎么放牛的，真实的牧场主还真是一股子老地主的味儿···
第一季的剧情问题不大，Dutton家族、印第安人、州政府和开发商之间的剧情能还顶住，还能顺带看看cowboy放牛。不过后续季的剧情会出乎意料··的烂，简直看不懂，刷新编剧水平下限
聚焦到本剧的内核，为什么这么多人喜欢这部剧，就是因为《黄石》不仅讲述了真实的cowboy的生活（甚至后面还拍了点真牧场的cowboy生活），同时反映了现代社会发展背景下，老牧场难以生存的现状，而cowboy、private land又是美利坚文化的核心，不仅是Dutton家族固执地想保留这个放牧的模式，甚至有种美利坚城市发展和本地文化的冲突对抗。
我可以负责的说，剧情肯定是一季比一季烂，甚至烂到主线剧情看不了。不过如果还出续集，我看这部剧的优先级会比其他所有的都高。&lt;/p&gt;</description><content:encoded>&lt;p&gt;​
刚把《黄石》系列看完，决定写点最近看的美剧，总共十一部，小评一下，写点东西~&lt;/p&gt;
&lt;p&gt;《黄石》&lt;/p&gt;
&lt;p&gt;《黄石》已经到第五季了，看样子还得继续拍。刚开始看《黄石》的时候，确实有种陷进去的感觉，很美很宏伟的电视剧，画面很棒风景很优美。而且还可以了解真实的老美是怎么放牛的，真实的牧场主还真是一股子老地主的味儿···
第一季的剧情问题不大，Dutton家族、印第安人、州政府和开发商之间的剧情能还顶住，还能顺带看看cowboy放牛。不过后续季的剧情会出乎意料··的烂，简直看不懂，刷新编剧水平下限
聚焦到本剧的内核，为什么这么多人喜欢这部剧，就是因为《黄石》不仅讲述了真实的cowboy的生活（甚至后面还拍了点真牧场的cowboy生活），同时反映了现代社会发展背景下，老牧场难以生存的现状，而cowboy、private land又是美利坚文化的核心，不仅是Dutton家族固执地想保留这个放牧的模式，甚至有种美利坚城市发展和本地文化的冲突对抗。
我可以负责的说，剧情肯定是一季比一季烂，甚至烂到主线剧情看不了。不过如果还出续集，我看这部剧的优先级会比其他所有的都高。&lt;/p&gt;
&lt;p&gt;个人喜好：⭐️⭐️⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;推荐指数：⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;《1923》&lt;/p&gt;
&lt;p&gt;《黄石》系列剧，黄石的前传。《黄石》可能是因为太出名了，导致这个前传《1923》明星有点多，从一开始的印象就不好。这部剧可能是因为考虑到《黄石》剧情不好看，如果仅仅只是写牛仔的话，其实很难有好看的剧本，所以《1923》加入了两条支线剧情。但是加入支线剧情又导致另一个问题，这部剧没有那么黄石，剧情不停的剪切，没有“慢节奏”的黄石既视感。
印第安女孩的剧情看上去是完全与主线脱节的，不知道什么时候能接上。但是这条印第安女孩剧情感觉还不错。印第安人的土地被掠夺，他们的子女还要被送到福利院去强行接受白人的宗教洗脑。这条支线确实有黄石的内核在里面，印第安人也是冷血杀手设定，没有那种子弹都打中身体了还要搞点政治的违和感。剧情流畅不拖沓，这条支线比较好看。
而非洲剧情支线···虽然也能拍点风景，但是确实没有Dutton牧场好看，没有那个感觉。而他们出了非洲就有点拖剧情了，重点描写的是时代背景下的壮美爱情故事，但是这跟黄石有啥关系呢···而且这条线等了一整季都没有聚拢到主线剧情去···为了一个人物，铺垫了一整季，说是Dutton牧场的希望都在他身上，立意太高了，本身这条支线剧情也没那么好看，第二季剧情大概率是大扑街~
《1923》前面还有点牧场反抗时代洪流的剧情，后面纯拖剧情，连放牛的戏都不拍了，完全没看点，打又打不起，有点烂。一季总共才8集，剧情到一半就开始摆烂，啥黄石没学到就学到了烂尾。
其实能看出来这部剧是想继承黄石，但有想搞点新东西，比如拍那个时代的美国和欧洲（甚至非洲殖民），但是又整了个四不像。想重回那个时代的话，推荐《大西洋帝国》，时间线都是禁酒令后，比这个剧有时代感的多。&lt;/p&gt;
&lt;p&gt;个人喜好：⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;推荐指数：⭐️⭐️&lt;/p&gt;
&lt;p&gt;《1883》&lt;/p&gt;
&lt;p&gt;《1883》，宏伟悲壮的西部牛仔片，《黄石》系列剧，《黄石》前传的前传。像在看一部史诗，意犹未尽。已经不仅仅是一部简单的电视剧，拍摄风格甚至有文学性和艺术性，同时又承载了一部分美利坚的开拓历史，那个时候美国刚结束内战没多久，百废待兴···
因为个人很喜欢《黄石》这类电视剧，《黄石》拍摄风格很合口味，但是正传剧情极度拉胯，甚至只想看他们在ranch骑马就行了，不想看主线剧情…《1883》弥补了这个缺憾，不要太多的复杂剧情——但也不要拉——就行了，看看valley，看看马，再来点宏伟的BGM，代入感很强。
《1883》整部剧其实也没有多少剧情，但是讲了一个很完整的故事。美利坚刚刚结束内战，正处在一个无主无法的时代，牛仔、劫匪、治安官、欧洲移民、印第安人···有一部分老套的西部牛仔骑马互射剧情，但更多的是关注牛仔的生活和移民对自由的向往，不过追求自由的道路上充满着艰辛：窃马贼、印第安部落、响尾蛇、龙卷风、还有这片无情的土地。很有深度的电视剧，除了女主的鼻涕扣分项外其他没有槽点，剧情是难得的完整不多不少，非常非常推荐。
摘一段喜欢的描述牛仔的台词&lt;/p&gt;
&lt;p&gt;个人喜好：⭐️⭐️⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;推荐指数：⭐️⭐️⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;《塔尔萨之王》&lt;/p&gt;
&lt;p&gt;爽片。70多岁的史泰龙主演，关了几十年的老黑帮重掌小城市黑道秩序，”不是我适应不了，是现在的人规矩有问题“，俺老派黑帮是讲规矩滴~剧情没什么槽点，没有拖沓，爽看。不知道后面还拍不拍了&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;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;/p&gt;
&lt;p&gt;一个系列总共4季已完结。剧集发生在1920s的美国，刚刚颁布禁酒令，妇女站在酒吧门口呼吁女性权利，政客为了拉票支持女性但私下都做着贩酒生意，黑帮从车上下来穿着大衣拿着汤普森冲锋枪突突···大西洋帝国就是说的大西洋城（Atlantic City，在纽约下面一点）的黑帮帝国，靠着贩酒建造了富可敌国的帝国。相信不少人看过《美国往事》，可以把这部戏近似看成它的电视剧版。这部戏一言难尽，只有一季一季讲。
第一季神中神，有很多不可描述的画面，剧情不能说顺畅而是神乎其神，女性、黑人、走私酒、爵士乐、黑帮斗争、一战士兵···黑帮已经实际控制了这个城市，连报社都不想听市长说的什么。
第二季为第一季的续集，也很不错。
第三季槽点就来了，它不像前两季的续集（虽然有些剧情有衔接），但是完全可以独立出来看。你说他剧情不好吧，是的他很脱节，但是说他烂嘛，单领出来没毛病甚至有点好看。这一季有很多精彩桥段：半脸人一个打十个、辣妈惊为天人的剧情、长段的黑人solo blues，都超棒！
第四季槽点满满，我以为我最喜欢的角色沉寂了3季总该粉墨登场来点作用了，结果草草收场，编剧你要不就不要把他印在封面上好吗？搞得好像有什么大动作，给我期待半天···。第四季男主高度太高了感觉不好推动剧情（其实第三季就有这种感觉），第四季唯一亮点就是男主小时候的剧情，算是男主线完美收场。
有很多人物的后期剧情不太好，但是有很多人物的中期剧情又太精彩了···虽然这部剧人气不高，但是还是拿过奖的，而且能看到很多桥段被后面的一些高人气美剧借鉴。比如《绝美毒师》炸鸡叔桥段借鉴半脸男，《权力的游戏》托曼国王自杀桥段“完全”借鉴管家自杀···
个人很喜欢这部剧，身临其境的感受那个年代的繁华都市、奢靡的城市生活、地下酒吧的爵士乐、黑帮···非常放得开的剧情（指任何东西都放得开），系列整体好看，很有时代感。&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;p&gt;推荐指数：⭐️⭐️⭐️⭐️⭐️&lt;/p&gt;
&lt;p&gt;《太平洋战争》&lt;/p&gt;
&lt;p&gt;《太平洋战争》拍在《兄弟连》前面不久，其实是很好看的一部剧，但是奈何后面出了个妖怪，这部剧名气没那么高。《兄弟连》说的是二战美国的欧洲战场，这部戏说的是太平洋战场。很神奇的是，这两部剧就跟这两个战场一样，欧洲战场更为人所知，剧集也是一样的···甚至在电视剧中，同一饭桌上，欧洲战场的soldier炫耀缴获的德军万旗，而太平洋战场的soldier却什么都没拿到，略显没落。
虽然不太出名，但是非常非常推荐的一部剧。&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;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;最后
都是值得一看的剧，也有很多神剧。有些剧没有找到熟肉硬啃生的，比如黄石系列剧《1883》，因为没有很复杂的对话所以也啃过去了（旁白很有水平）···算是生肉首开。
这些剧基本都是近半年看的，所以拉起来一起说说。更早时候看的美剧其实也有很多精彩的，印象深刻，埋个坑有闲心了再聊吧~
希望下半年也能找到好剧。&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;</content:encoded></item><item><title>关于</title><link>https://lastdba.com/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lastdba.com/about/</guid><description>&lt;p&gt;你好，我是 &lt;strong&gt;liuzhilong62&lt;/strong&gt;，一名 PostgreSQL DBA。&lt;/p&gt;
&lt;p&gt;这个博客记录了我在 PostgreSQL 数据库领域的学习与实践，涵盖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL 内功修炼&lt;/strong&gt; — 深入理解 PG 内核机制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;案例分析&lt;/strong&gt; — 真实生产环境故障排查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;源码解析&lt;/strong&gt; — 阅读 PG 源码的笔记&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;论文解读&lt;/strong&gt; — 数据库领域论文精读&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读书笔记&lt;/strong&gt; — 技术书籍阅读总结&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;📡 微信公众号：&lt;strong&gt;最后的DBA&lt;/strong&gt;&lt;/p&gt;</description><content:encoded>&lt;p&gt;你好，我是 &lt;strong&gt;liuzhilong62&lt;/strong&gt;，一名 PostgreSQL DBA。&lt;/p&gt;
&lt;p&gt;这个博客记录了我在 PostgreSQL 数据库领域的学习与实践，涵盖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL 内功修炼&lt;/strong&gt; — 深入理解 PG 内核机制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;案例分析&lt;/strong&gt; — 真实生产环境故障排查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;源码解析&lt;/strong&gt; — 阅读 PG 源码的笔记&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;论文解读&lt;/strong&gt; — 数据库领域论文精读&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读书笔记&lt;/strong&gt; — 技术书籍阅读总结&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;📡 微信公众号：&lt;strong&gt;最后的DBA&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以在以下平台找到我：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/liuzhilong62" target="_blank" rel="noreferrer"&gt;liuzhilong62&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CSDN: &lt;a href="https://liuzhilong.blog.csdn.net" target="_blank" rel="noreferrer"&gt;liuzhilong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;墨天轮: &lt;a href="https://www.modb.pro/u/4587" target="_blank" rel="noreferrer"&gt;liuzhilong62&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;X: &lt;a href="https://x.com/liuzhilong62" target="_blank" rel="noreferrer"&gt;@liuzhilong62&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>