<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://ivorySQL.org/zh-cn/blog</id>
    <title>IvorySQL Blog</title>
    <updated>2026-02-10T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://ivorySQL.org/zh-cn/blog"/>
    <subtitle>IvorySQL Blog</subtitle>
    <icon>https://ivorySQL.org/zh-cn/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[IvorySQL 5.0+：助力 Oracle 平滑过渡至 PostgreSQL 的里程碑式产品]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration"/>
        <updated>2026-02-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[IvorySQL：一种“先进、功能完备、开源且兼容 Oracle 的 PostgreSQL 数据库，始终致力于保持 100% 兼容性，并可作为最新 PostgreSQL 的无缝替代”。]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">IvorySQL</a>：一种“先进、功能完备、开源且兼容 Oracle 的 PostgreSQL 数据库，始终致力于保持 100% 兼容性，并可作为最新 PostgreSQL 的无缝替代”。</p>
<p>同时，这款引擎也是我们团队将各类外部 SQL 语句及应用适配至 PostgreSQL 时的首选工具！我们秉持平滑过渡、而非整体迁移的理念 —— 让旧数据库引擎向新引擎逐步切换，核心为降低迁移风险、优化实施效果。借助这类方案，能为实现这两大目标带来关键助力。</p>
<p>尽管 IvorySQL 最新主版本发布已有一段时间，但其中的全新特性依旧让我们倍感振奋，特此为大家分享。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="新特性概览">新特性概览<a href="https://ivorysql.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration#%E6%96%B0%E7%89%B9%E6%80%A7%E6%A6%82%E8%A7%88" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL 5.0 版本（<a href="https://github.com/IvorySQL/IvorySQL/releases/tag/IvorySQL_5.0" target="_blank" rel="noopener noreferrer" class="">5.0 发布说明</a>）于 2025 年 11 月 25 日发布，随后在 2025 年 12 月 18 日推出 5.1 版本（<a href="https://github.com/IvorySQL/IvorySQL/releases/tag/IvorySQL_5.1" target="_blank" rel="noopener noreferrer" class="">5.1 发布说明</a>）。这两个版本凝聚了 IvorySQL 团队的大量投入，不仅带来了多项高品质的功能优化，还完成了对 PostgreSQL 18 的兼容性适配。</p>
<p>IvorySQL v5 带来了一系列关键能力，包括：</p>
<ul>
<li class=""><strong>PLiSQL</strong> —— 兼容 Oracle PL/SQL 的子集</li>
<li class="">Oracle 兼容包支持</li>
<li class="">Oracle 风格序列支持</li>
<li class=""><strong>v5.0</strong> 增强能力包括：<code>ROWID</code>、<code>%TYPE</code>、<code>%ROWTYPE</code> 以及嵌套子函数</li>
</ul>
<p>我们尤其喜欢很多功能升级。</p>
<p>例如，IvorySQL 现在改进了 <code>NULL</code> 值处理逻辑，在兼容模式下（与 Oracle 的行为一致），<code>NULL</code> 值现在被视为空字符串，以避免迁移过程中出现错误。以 <code>SELECT CONCAT ('a' || NULL)</code> 语句为例，IvorySQL 将返回结果 <code>'a'</code>，而非沿用 PostgreSQL 默认的 <code>NULL</code> 值返回逻辑。</p>
<p>我们非常喜欢的一项增强功能是：你现在可以嵌套函数和存储过程。函数能够嵌入到其他函数内部（类似于 Oracle 的包，但更简单，仅使用私有方法）。这让你能够在一个地方集中组织复杂的逻辑。</p>
<p>与之类似，系统还增加了对 <code>DO [ LANGUAGE lang_name ] 代码块 [USING IN | OUT | IN OUT, ...]</code> 语法的支持。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="实测验证">实测验证<a href="https://ivorysql.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration#%E5%AE%9E%E6%B5%8B%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>目前，我们已基于该版本完成多类应用的迁移适配测试，适配对象规模跨度极大：既有仅包含少量包、存储过程及函数的轻量应用（约 10-50 个数据库对象），也有包含海量数据库对象的大型业务系统（约 5 万个对象，其中存储过程超 1 万个、数据库包达数百个）。</p>
<p>尽管后续仍需持续迭代、补充更多功能特性，但当前版本已能大幅降低从 Oracle 向 PostgreSQL 平滑过渡的实施成本，助力迁移工作高效落地。</p>
<p>若你计划亲自体验测试，IvorySQL 提供了丰富的快速上手方式，包括源码编译、容器部署等，甚至还支持 WASM 构建！WASM 的独特优势在于，无需在本地完成完整安装，即可在浏览器中直接运行 IvorySQL，便于快速验证语法兼容性并开展 PostgreSQL 体系的初步探索。</p>
<p>你可参照 IvorySQL 官方发布的<a href="https://www.ivorysql.org/blog/ivorysql-wasm/" target="_blank" rel="noopener noreferrer" class="">相关文章</a>，通过简单几步完成 IvorySQL-WASM 项目的本地部署。也可直接访问 IvorySQL 官网，体验<a href="https://trial.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">在线托管的 WASM 版本</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="后续规划">后续规划<a href="https://ivorysql.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration#%E5%90%8E%E7%BB%AD%E8%A7%84%E5%88%92" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>我们团队很高兴聘用 IvorySQL 项目的贡献者，目前我们团队已有多位贡献者加入 IvorySQL 的核心研发工作。其中 Cédric Villemain、Yasir Hussain Shah 等成员的贡献，已在 5.0 和 5.1 版本的发布说明中专门致谢 —— 未来我们还将吸纳更多优秀开发者参与项目建设。</p>
<p>针对下一个版本，我们已规划了多项重磅新特性开发工作，具体包括：</p>
<ul>
<li class=""><code>ENABLE / DISABLE</code> 约束语法支持</li>
<li class=""><code>UTL_FILE</code> 包新增适配</li>
<li class="">Oracle 风格的 <code>CREATE TRIGGER</code> 触发器体（无需预先创建函数）</li>
<li class="">支持 Oracle 旧式连接运算符 <code>(+)</code></li>
</ul>
<p>我们同样期待社区为下一个版本持续贡献的研发成果落地。目前已有多项优质功能正处于积极开发与合入阶段，例如项目新晋贡献者 Rophy Tsai 近期新增了 <code>DBMS_OUTPUT</code> 和 <code>DBMS_UTILITY</code> 包的适配支持 —— 这两个包是 Oracle 生态 SQL 代码库中应用极为广泛的工具包。该特性现已合入 IvorySQL 主分支，预计将随下一个小版本或主版本正式发布。</p>
<p>对于希望在无需对现有数据库逻辑和应用程序进行大量改造的前提下，完成向 PostgreSQL 迁移或探索 PostgreSQL 生态的开发者而言，IvorySQL（尤其是 5.x 系列版本）提供了一套切实可行的解决方案。直接迁移至 PostgreSQL 在部分场景下，可能需要对数据库对象和应用代码做出大量调整，而 IvorySQL 能够有效填补这一适配鸿沟，凭借更高的兼容性，助力开发者更平滑地完成 PostgreSQL 生态的落地与适配。</p>
<p>您还可以通过以下渠道深入了解 IvorySQL：</p>
<ul>
<li class="">官网 blog：<a href="https://www.ivorysql.org/zh-CN/blog" target="_blank" rel="noopener noreferrer" class="">https://www.ivorysql.org/zh-CN/blog</a></li>
<li class="">社区活动：<a href="https://www.ivorysql.org/zh-cn/events" target="_blank" rel="noopener noreferrer" class="">https://www.ivorysql.org/zh-cn/events</a></li>
<li class="">HOW 2025 相关会议录像：<a href="https://www.youtube.com/@ivorysql" target="_blank" rel="noopener noreferrer" class="">https://www.youtube.com/@ivorysql</a></li>
</ul>
<p>值得一提的是，2026 年的 HOW 大会已确定于 4 月 26 日至 28 日举行，<a href="https://jsj.top/f/uebqBc" target="_blank" rel="noopener noreferrer" class="">议题征集</a>截止日期为 2026 年 2 月 27 日。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="更多参考">更多参考<a href="https://ivorysql.org/zh-cn/blog/ivorysql-5.0-oracle-to-postgresql-migration#%E6%9B%B4%E5%A4%9A%E5%8F%82%E8%80%83" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://www.postgresql.org/about/news/ivorysql-50-released-major-oracle-compatibility-expansion-on-postgresql-180-foundation-3180/" target="_blank" rel="noopener noreferrer" class="">PostgreSQL.org 发布的 IvorySQL 5.0 公告</a></li>
<li class=""><a href="https://github.com/orgs/IvorySQL/projects/19" target="_blank" rel="noopener noreferrer" class="">GitHub 上的 IvorySQL 5.0 路线图</a></li>
</ul>]]></content>
        <author>
            <name>Yasir Hussain Shah</name>
            <uri>https://www.data-bene.io/en/team/yasir-hussain-shah/</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="migration" term="migration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[聚焦六大功能：PostgreSQL 18 新特性深度解析]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/analysis-of-pg-18-key-new-features</id>
        <link href="https://ivorySQL.org/zh-cn/blog/analysis-of-pg-18-key-new-features"/>
        <updated>2025-09-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[PostgreSQL 全球开发组于 2025 年 5 月 8 日发布了 PostgreSQL 18 的首个 Beta 版本，正式版也已于 9 月 25 日正式上线。本文 IvorySQL 社区将为大家拆解 PostgreSQL 18 的六大亮点特性。]]></summary>
        <content type="html"><![CDATA[<p>PostgreSQL 全球开发组于 2025 年 5 月 8 日发布了 PostgreSQL 18 的首个 Beta 版本，正式版也已于 9 月 25 日正式上线。本文 IvorySQL 社区将为大家拆解 PostgreSQL 18 的六大亮点特性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一pg-异步-ioaio框架迈出打破同步阻塞瓶颈的第一步">一、PG 异步 I/O（AIO）框架：迈出打破同步阻塞瓶颈的第一步<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%B8%80pg-%E5%BC%82%E6%AD%A5-ioaio%E6%A1%86%E6%9E%B6%E8%BF%88%E5%87%BA%E6%89%93%E7%A0%B4%E5%90%8C%E6%AD%A5%E9%98%BB%E5%A1%9E%E7%93%B6%E9%A2%88%E7%9A%84%E7%AC%AC%E4%B8%80%E6%AD%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>PostgreSQL 18 全新引入异步 I/O 子系统。新机制允许<strong>特定场景下</strong>并行执行多个异步预读操作，CPU 无需等待数据返回即可继续推进查询，一定程度上降低了等待损耗。此框架为 PG 未来更深入更彻底的异步 I/O 性能优化奠定基础，迈出了第一步。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心提升场景">核心提升场景<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%A0%B8%E5%BF%83%E6%8F%90%E5%8D%87%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p><strong>【当前仅实现异步读，没有实现异步写】</strong> 所有 Seq Scan 场景下通过适配过异步 I/O 的 ReadStream 设施可实现并行化顺序预读，提升 Seq Scan 的性能，效果好于原有 <code>posix_fadvice</code> 的建议性预读。尤其在云存储场景下单次阻塞读 I/O 相比本地 I/O 所需时间更长，异步 I/O 加持下的并行化预读的优势更加明显。目前异步 I/O 已支持顺序扫描、位图堆扫描和 VACUUM 操作的异步读取，早期测试显示，读取密集型查询性能可提升 2-3 倍。</p>
<p>如图所示：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250926-aio-drawio-99a351b1a3a0b55a3452defb40d3eff1.png" width="2283" height="1503" class="img_ev3q"></p>
<p>使用了异步 I/O 的 ReadStream 机制可以在收到读请求后异步地预读后续可能使用的 buffer。而在使用同步 I/O 方式在每次请求读取 buffer 时，都要等待 I/O 操作完成，这样降低了系统吞吐量。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用方法">使用方法<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># - I/O -</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">#backend_flush_after = 0		# measured in pages, 0 disables</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">effective_io_concurrency = 300		# 1-1000; 0 disables issuing multiple simultaneous IO requests</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">maintenance_io_concurrency = 300	# 1-1000; same as effective_io_concurrency</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_max_combine_limit = 256kB		# usually 1-128 blocks (depends on OS)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    # (change requires restart)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_combine_limit = 256kB		# usually 1-128 blocks (depends on OS)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_method = io_uring # worker, io_uring, sync</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    # (change requires restart)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_max_concurrency = 128		# Max number of IOs that one process</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    # can execute simultaneously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    # -1 sets based on shared_buffers</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    # (change requires restart)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">#io_workers = 3				# 1-32;</span><br></span></code></pre></div></div>
<p>用户可选择三种不同的 <code>io_method</code> 启用异步 I/O，分别是：</p>
<ul>
<li class=""><code>worker</code> 若干后台 I/O workers 接收处理后端进程的 I/O 请求。</li>
<li class=""><code>io_uring</code> Linux 系统中 io_uring 子系统通过操作系统内核线程处理 PG 的 I/O 请求。</li>
<li class=""><code>sync</code> 满足异步 I/O 框架接口要求的同步 I/O。</li>
</ul>
<p>要启用异步 I/O，用户需要根据自身情况设定上述 GUC 参数。其中每个进程能够拥有的最大异步 I/O 句柄为 <code>io_max_concurrency</code>，用户可以将其置 <code>-1</code>，使数据库自行选择合适的值。若自行选择的值太大，则可能因为异步 I/O 所占空间太大而无法启动数据库；若自行选择的值太小则无法完全发挥出异步 I/O 性能。</p>
<p>启动数据库后，用户可通过 <code>pg_aios</code> 视图实时地获取当前系统异步 I/O 执行状况:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">postgres=# select * from pg_aios;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-[ RECORD 1 ]---+-------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pid             | 85834</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_id           | 14208</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">io_generation   | 204</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">state           | SUBMITTED</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">operation       | readv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">off             | 116252672</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">length          | 8192</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">target          | smgr</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">handle_data_len | 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">raw_result      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">result          | UNKNOWN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">target_desc     | block 14191 in file "base/5/16427"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">f_sync          | f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">f_localmem      | f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">f_buffered      | t</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span></code></pre></div></div>
<p>各列含义详见<a href="https://www.postgresql.org/docs/18/view-pg-aios.html" target="_blank" rel="noopener noreferrer" class="">官方文档</a>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="框架设计">框架设计<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PG 18 引入异步 I/O 框架，支持通过 GUC 参数灵活配置异步 I/O：包括实现方式（<code>io_method</code>，可选 worker、io_uring 或 sync）、并发规模（如 <code>*_io_concurrency</code>、<code>io_max_concurrency</code>）及实现相关参数（如 <code>io_workers</code>）。</p>
<p>该框架对 I/O 目标（当前支持 smgr，未来计划支持 WAL）和不同阶段、不同数据源(shared buffer/local buffer)的行为进行了抽象（通过 <code>PgAioHandleCallbacks</code> 结构），以支持后续扩展。相关内存于启动时在共享内存中分配，后续不再缩放。进程按编号访问所属异步 I/O 资源，句柄通过 generation 号标记复用。</p>
<p>目前该版本异步 I/O 主要提供对 smgr 的异步读支持，尚不支持 WAL 异步读写，smgr 的异步写入功能仍在开发中。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="对原有设施的修改">对原有设施的修改<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%AF%B9%E5%8E%9F%E6%9C%89%E8%AE%BE%E6%96%BD%E7%9A%84%E4%BF%AE%E6%94%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class=""><strong>扩展 smgr 接口</strong>：新增 <code>smgr_startreadv</code> 方法以支持异步读取。</li>
<li class=""><strong>实现回调结构</strong>：smgr 需实现 <code>PgAioTargetInfo</code> 和 <code>PgAioHandleCallBacks</code> 回调结构。</li>
<li class=""><strong>适配现有模块</strong>：smgr 和 buffer manager 等模块需填充异步 I/O 抽象结构以兼容框架。</li>
<li class=""><strong>PG 临界区处理</strong>：同步 I/O 可在 PG 临界区内发起；异步 I/O 因分段执行且带回调，需移除回调中可能失败的操作（临界区内一切操作不能失败，如用<code>RelPathStr</code>替代 palloc 的<code>char*</code>字符串）以确保安全。</li>
<li class=""><strong>优化上层接口</strong>：利用异步 I/O 改造 ReadStream 等接口，实现真预读，大幅提升顺序扫描、pg_prewarm 及 ANALYZE 等操作的 I/O 性能，效果优于原有 posix_fadvise 方案。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用注意及未来展望">使用注意及未来展望<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E5%8F%8A%E6%9C%AA%E6%9D%A5%E5%B1%95%E6%9C%9B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">**io_uring 需要较新内核：**旧版 Linux Kernel 不支持 io_uring。某些早期版本内核虽然支持 io_uring，但功能和性能表现与新内核有一定差距。</li>
<li class=""><strong>架构限制并发粒度</strong>：受多进程架构所限，PG 异步 I/O 期间可并行运行的计算任务较少，难以实现更细粒度的任务级异步。当前主要性能收益集中于<strong>ReadStream 顺序预读</strong>及等并行 I/O 操作。</li>
<li class=""><strong>未来可能的性能提升</strong>：Linux io_uring 支持直接 I/O（DIO）特性，为在 PG 中启用 DIO 奠定基础。未来启用直接 I/O 可免除双重 buffer(OS 层面对 I/O 数据进行 buffer，PG 层面对 I/O 进行 buffer)以减少不必要的数据复制。在高速 NVMe 上还配合 DIO 启用<strong>IORING_SETUP_IOPOLL</strong>选项使用轮训方式检查 I/O 完成情况，还可以进一步提升性能。</li>
<li class=""><strong>未来更多的异步 I/O 后端</strong>：除了<code>sync</code>模式，正式版的 PostgreSQL 18 仅支持 <code>worker</code> 和 <code>io_uring</code> 两种异步 I/O 后端。目前异步 I/O 框架设计已基本完备，未来版本有望支持 Windows IORing，IOCP，以及 Posix 异步 I/O 等 I/O 后端，为用户提供更多选择。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 异步 I/O 框架提升数据库系统 I/O 能力，同时也增强了 PostgreSQL 架构的可扩展性，用户只需要根据自身情况修改 GUC 参数即可获取到异步 I/O 带来的好处。目前异步 I/O 框架设计基本完备，后期支持其他异步 I/O 后端也将非常方便。任意平台 Postgres 用户可以尝试 <code>io_method = worker</code>或者<code>sync</code> 若要在非官方适配 io_uring 的旧 Linux 内核发行版上使用 io_uring 后端，需要进行充分测试后再使用。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二-跳跃式扫描让-b-树索引-提速换挡">二、 跳跃式扫描：让 B 树索引 “提速换挡”<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BA%8C-%E8%B7%B3%E8%B7%83%E5%BC%8F%E6%89%AB%E6%8F%8F%E8%AE%A9-b-%E6%A0%91%E7%B4%A2%E5%BC%95-%E6%8F%90%E9%80%9F%E6%8D%A2%E6%8C%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在 PostgreSQL 18 之前的版本中，多列 B 树索引可用于包含该索引中任意子集列的查询条件，在对起始（最左侧）列施加约束时最为高效。对前导列的等式约束，加上对第一个不带有等式约束的列的任何不等式约束，用于限制要扫描的索引部分。</p>
<p>例如，给定一个基于（a，b，c）非空字段的升序索引和查询条件 WHERE a = 5 AND b &gt;= 42 AND c &lt; 77，该索引将从具有 a = 5 和 b = 42 的第一个条目开始扫描，一直扫描到最后具有 a = 5 的条目。 具有 c &gt;= 77 的索引条目将被跳过，但它们仍需扫描。</p>
<p>原则上，这种索引可以用于对 b 和/或 c 有约束条件而对 a 没有约束条件的查询——但必须扫描整个索引，所以在大多数情况下优化器更倾向于对表进行顺序扫描表，而非利用索引扫描。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心提升场景-1">核心提升场景<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%A0%B8%E5%BF%83%E6%8F%90%E5%8D%87%E5%9C%BA%E6%99%AF-1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>从 PostgreSQL 18 开始：</p>
<p>如果 B 树索引扫描能够应用跳跃式扫描（SKIP SCAN），在遍历索引时应用每个列的约束，可以减少索引的读取。跳跃式扫描的工作原理是内部生成一个动态等式约束，该约束与索引列中的每个可能值相匹配。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="效果测试">效果测试<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%95%88%E6%9E%9C%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>对比版本：</p>
<p><strong>PostgreSQL 17 vs PostgreSQL 18</strong></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="表结构与索引">表结构与索引<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%8E%E7%B4%A2%E5%BC%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> t1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">c1 </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">c2 </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">c3 </span><span class="token keyword" style="color:#00009f">float</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">WITH</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">fillfactor</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">80</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INDEX</span><span class="token plain"> idx_t1_c1c2 </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> t1</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="数据生成">数据生成<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> t1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">10000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> generate_series</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">1000000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> g</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="通过-copy-导入数据">通过 COPY 导入数据<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E9%80%9A%E8%BF%87-copy-%E5%AF%BC%E5%85%A5%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">COPY t1 </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'/.../t1.csv'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WITH</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">FORMAT csv</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="查询语句-使用复合索引的第二个列">查询语句 使用复合索引的第二个列<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5-%E4%BD%BF%E7%94%A8%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E7%9A%84%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%88%97" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">EXPLAIN</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ANALYZE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> t1 </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> c2</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="postgresql-17-执行计划-选择使用并行顺序扫描">PostgreSQL 17 执行计划 选择使用并行顺序扫描<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#postgresql-17-%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92-%E9%80%89%E6%8B%A9%E4%BD%BF%E7%94%A8%E5%B9%B6%E8%A1%8C%E9%A1%BA%E5%BA%8F%E6%89%AB%E6%8F%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">                                                    QUERY PLAN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-------------------------------------------------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Gather  (cost=1000.00..12986.33 rows=100 width=16) (actual time=1.125..76.076 rows=90 loops=1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Planned: 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Launched: 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   -&gt;  Parallel Seq Scan on t1  (cost=0.00..11976.33 rows=42 width=16) (actual time=1.414..68.624 rows=30 loops=3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Filter: (c2 = 100)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Rows Removed by Filter: 333303</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning Time: 0.792 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution Time: 76.165 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(8 rows)</span><br></span></code></pre></div></div>
<p>关闭顺序扫描强制选择索引扫描，并非最优计划，执行更慢。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">                                                        QUERY PLAN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--------------------------------------------------------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Index Scan using idx_t1_c1c2 on t1  (cost=0.42..18773.42 rows=100 width=16) (actual time=1.846..100.758 rows=90 loops=1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Index Cond: (c2 = 100)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning Time: 0.147 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution Time: 100.806 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(4 rows)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="postgresql-18-执行计划选择使用索引扫描可以看出跳跃式扫描执行效率提升幅度非常大">PostgreSQL 18 执行计划选择使用索引扫描，可以看出跳跃式扫描执行效率提升幅度非常大<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#postgresql-18-%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E9%80%89%E6%8B%A9%E4%BD%BF%E7%94%A8%E7%B4%A2%E5%BC%95%E6%89%AB%E6%8F%8F%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%E8%B7%B3%E8%B7%83%E5%BC%8F%E6%89%AB%E6%8F%8F%E6%89%A7%E8%A1%8C%E6%95%88%E7%8E%87%E6%8F%90%E5%8D%87%E5%B9%85%E5%BA%A6%E9%9D%9E%E5%B8%B8%E5%A4%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">                                                        QUERY PLAN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">---------------------------------------------------------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Index Scan using idx_t1_c1c2 on t1  (cost=0.42..3900.84 rows=100 width=16) (actual time=0.225..11.464 rows=90.00 loops=1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Index Cond: (c2 = 100)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Index Searches: 1002</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit=3096</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning Time: 0.141 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution Time: 11.522 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(6 rows)</span><br></span></code></pre></div></div>
<p>关闭索引扫描和位图扫描强制选择顺序扫描。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">postgres=# EXPLAIN ANALYZE SELECT * FROM t1 WHERE c2=100;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                                      QUERY PLAN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">----------------------------------------------------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Gather  (cost=1000.00..12986.33 rows=100 width=16) (actual time=1.486..86.881 rows=90.00 loops=1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Planned: 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Launched: 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit=6768</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   -&gt;  Parallel Seq Scan on t1  (cost=0.00..11976.33 rows=42 width=16) (actual time=2.758..78.712 rows=30.00 loops=3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Filter: (c2 = 100)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Rows Removed by Filter: 333303</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Buffers: shared hit=6768</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning Time: 0.141 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution Time: 86.926 ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(10 rows)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用注意">使用注意<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>跳跃式扫描目前只能支持等值比较条件。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结-1">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93-1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 的索引跳跃式扫描，使得多列 BTREE 索引能够被那些仅对第二个或之后的索引列进行等值引用的查询使用，大幅减少索引扫描需要访问的条目，使其效率得到明显提升。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三-虚拟生成列存储与计算的-灵活平衡">三、 虚拟生成列：存储与计算的 “灵活平衡”<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%B8%89-%E8%99%9A%E6%8B%9F%E7%94%9F%E6%88%90%E5%88%97%E5%AD%98%E5%82%A8%E4%B8%8E%E8%AE%A1%E7%AE%97%E7%9A%84-%E7%81%B5%E6%B4%BB%E5%B9%B3%E8%A1%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>PostgreSQL 18 开发体验相关的特性，聚焦于简化开发流程、提升代码灵活性，让开发者更高效地利用 PostgreSQL 能力。</p>
<p>IvorySQL 数据库长期致力于 Oracle 特性兼容，其中包含了一项虚拟列的语法兼容：</p>
<p><code>column [datatype][generated always] AS (column_expression)[VIRTUAL]</code></p>
<p>这次 PostgreSQL 18 终于也带来了虚拟列功能。虚拟列是一种不存储数据的表列，其值在查询时通过动态计算得出。与存储列相比，虚拟列节省了列存储空间，查询虚拟列值时通过计算虚拟列表达式的值作为该列的值。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="基本语法">基本语法<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 中虚拟列的语法和存储列的语法相似，新增加关键字<strong>VIRTUAL</strong>，当省略 STORED 和 VIRTUAL 关键字时默认为虚拟列。其语法如下所示：</p>
<p><code>GENERATED ALWAYS AS ( generation_expr ) [ STORED | VIRTUAL ]</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="虚拟列用例">虚拟列用例<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%99%9A%E6%8B%9F%E5%88%97%E7%94%A8%E4%BE%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>虚拟列的标识是在列的限制条件中表示的，通过虚拟列的限制语法标识列为虚拟列，以下为虚拟列表的创建、查询和新增虚拟列：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 创建包含虚拟列的表，其中price_with_tax为虚拟列</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> products </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id </span><span class="token keyword" style="color:#00009f">SERIAL</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">PRIMARY</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">KEY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name </span><span class="token keyword" style="color:#00009f">TEXT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    price </span><span class="token keyword" style="color:#00009f">NUMERIC</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    tax_rate </span><span class="token keyword" style="color:#00009f">NUMERIC</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.20</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    price_with_tax </span><span class="token keyword" style="color:#00009f">NUMERIC</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> GENERATED ALWAYS </span><span class="token keyword" style="color:#00009f">AS</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">price </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> VIRTUAL</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 插入数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> products </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Laptop'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000.00</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 查询数据（虚拟列自动计算）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price_with_tax </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> products</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain">  price  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> tax_rate </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> price_with_tax</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">--------+---------+----------+----------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Laptop </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000.00</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain">     </span><span class="token number" style="color:#36acaa">0.20</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain">        </span><span class="token number" style="color:#36acaa">1200.00</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">row</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">--为表添加虚拟列</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">ALTER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> products </span><span class="token keyword" style="color:#00009f">ADD</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">COLUMN</span><span class="token plain"> selling_price </span><span class="token keyword" style="color:#00009f">NUMERIC</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">GENERATED ALWAYS </span><span class="token keyword" style="color:#00009f">AS</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    price </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> virtual</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="实现原理浅析">实现原理浅析<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E6%B5%85%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="虚拟列的创建">虚拟列的创建<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%99%9A%E6%8B%9F%E5%88%97%E7%9A%84%E5%88%9B%E5%BB%BA" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>创建的表中虚拟列的存储方式和普通列的存储方式类似，其列信息都存储在 pg_attribute 系统表中，其中 attgenerated 列存储生成列信息，如果该列的值为's'，表示该列为存储列。PostgreSQL 18 新增的虚拟列在该字段中的标识符为'v'，并且将虚拟列的表达式存储于 pg_attrdef 系统表中。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">--查看虚拟列信息，其attgenerated为v表示该列为虚拟列</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">postgres</span><span class="token operator" style="color:#393A34">=</span><span class="token comment" style="color:#999988;font-style:italic"># select * from pg_attribute where attname='price_with_tax';</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"> RECORD </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">]</span><span class="token comment" style="color:#999988;font-style:italic">--+---------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attrelid       </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">16388</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attname        </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> price_with_tax</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">atttypid       </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1700</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attlen         </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attnum         </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">atttypmod      </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">655366</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attndims       </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attbyval       </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attalign       </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> i</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attstorage     </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> m</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attcompression </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attnotnull     </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">atthasdef      </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> t</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">atthasmissing  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attidentity    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attgenerated   </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> v</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attisdropped   </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attislocal     </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> t</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attinhcount    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attcollation   </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attstattarget  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attacl         </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attoptions     </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attfdwoptions  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">attmissingval  </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">--查看虚拟列表达式存储，可以看到以下表达式为虚拟列表达式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">postgres</span><span class="token operator" style="color:#393A34">=</span><span class="token comment" style="color:#999988;font-style:italic"># select pg_get_expr(adbin, adrelid) from pg_attrdef where adnum = 5;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             pg_get_expr</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-------------------------------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">price </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">numeric</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">row</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="虚拟列的插入或更新">虚拟列的插入或更新<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%99%9A%E6%8B%9F%E5%88%97%E7%9A%84%E6%8F%92%E5%85%A5%E6%88%96%E6%9B%B4%E6%96%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>由于虚拟列的数据不占据存储空间，所以任何指定更新或插入虚拟列的操作都将被限制。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">--指定插入虚拟列</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> products </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price_with_tax</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Laptop'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000.00</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.20</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ERROR:  cannot </span><span class="token keyword" style="color:#00009f">insert</span><span class="token plain"> a non</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">value</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">into</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">column</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"price_with_tax"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">DETAIL:  </span><span class="token keyword" style="color:#00009f">Column</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"price_with_tax"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">is</span><span class="token plain"> a generated </span><span class="token keyword" style="color:#00009f">column</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">--指定更新虚拟列</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">update</span><span class="token plain"> products </span><span class="token keyword" style="color:#00009f">set</span><span class="token plain"> price_with_tax </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Laptop'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ERROR:  </span><span class="token keyword" style="color:#00009f">column</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"price_with_tax"</span><span class="token plain"> can only be updated </span><span class="token keyword" style="color:#00009f">to</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">DETAIL:  </span><span class="token keyword" style="color:#00009f">Column</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"price_with_tax"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">is</span><span class="token plain"> a generated </span><span class="token keyword" style="color:#00009f">column</span><span class="token punctuation" style="color:#393A34">.</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="虚拟列的查询">虚拟列的查询<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%99%9A%E6%8B%9F%E5%88%97%E7%9A%84%E6%9F%A5%E8%AF%A2" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>PostgreSQL 18 中查询虚拟列的实现是在生成执行计划阶段完成。在逻辑重写优化阶段，判断查询的范围表中是否包含虚拟列，如果包含虚拟列，则将该虚拟列的表达式从 pg_attrdef 中获取出来并替换原虚拟列名。这样查询虚拟列的值就相当于计算其表达式的值，即 <code>select price_with_tax</code> 相当于 <code>select (price \* ('1'::numeric + tax_rate)) as price_with_tax</code>。可以看到以下虚拟列被替换成了其表达式：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">postgres</span><span class="token operator" style="color:#393A34">=</span><span class="token comment" style="color:#999988;font-style:italic"># explain verbose SELECT name, price, tax_rate, price_with_tax</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> products</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                              QUERY </span><span class="token keyword" style="color:#00009f">PLAN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">----------------------------------------------------------------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Seq Scan </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">public</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">products  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.23</span><span class="token number" style="color:#36acaa">.12</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">750</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">76</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Output: name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> price</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">price </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'1'</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">numeric</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> tax_rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="适用场景">适用场景<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ul>
<li class="">当考虑存储空间时，可以使用虚拟列，因为虚拟列不占用磁盘空间。</li>
<li class="">当列的值需要根据依赖的列变化而变化时，需要使用虚拟列。因为虚拟列的值是动态获取的。</li>
<li class="">当虚拟列表达式简单时，可以使用虚拟列。因为查询虚拟列需消耗 CPU 资源，表达式复杂会消耗太多 CPU 资源。</li>
<li class="">因为 Oracle 中有虚拟列功能，更加方便 Oracle 的虚拟列迁移至 PostgreSQL 中。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="待完善部分">待完善部分<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%BE%85%E5%AE%8C%E5%96%84%E9%83%A8%E5%88%86" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>一些功能目前尚不支持，但可能会作为增量功能在后续的版本中添加：</p>
<ul>
<li class="">在虚拟列上创建索引或使用虚拟列。</li>
<li class="">虚拟列上也没有唯一约束。</li>
<li class="">虚拟列上的扩展统计信息。</li>
<li class="">虚拟列上的外键约束。</li>
<li class="">虚拟列上的非空约束（支持检查约束）。</li>
<li class="">ALTER TABLE / DROP EXPRESSION。</li>
<li class="">虚拟列不能具有域类型。</li>
<li class="">逻辑复制不支持虚拟列。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结-2">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93-2" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>虚拟列与普通列和存储列有着本质的不同，因为虚拟列的值不占磁盘空间，其获取值的方式也与普通列和存储列不同，普通列或存储列需要从磁盘获取数据，而虚拟列是通过动态计算获取虚拟列的值。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四uuid-功能增强有序性与易用性提升">四、UUID 功能增强：有序性与易用性提升<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%9B%9Buuid-%E5%8A%9F%E8%83%BD%E5%A2%9E%E5%BC%BA%E6%9C%89%E5%BA%8F%E6%80%A7%E4%B8%8E%E6%98%93%E7%94%A8%E6%80%A7%E6%8F%90%E5%8D%87" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="传统-uuid-的无序性是其用作主键的主要痛点">传统 UUID 的无序性是其用作主键的主要痛点：<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BC%A0%E7%BB%9F-uuid-%E7%9A%84%E6%97%A0%E5%BA%8F%E6%80%A7%E6%98%AF%E5%85%B6%E7%94%A8%E4%BD%9C%E4%B8%BB%E9%94%AE%E7%9A%84%E4%B8%BB%E8%A6%81%E7%97%9B%E7%82%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>传统 UUID（尤其是 v4）的完全随机性是其作为数据库主键的痛点：</p>
<ul>
<li class="">UUID 随机生成，插入位置不确定，导致索引树频繁分裂和重组，大幅降低写入性能。</li>
<li class="">破坏聚簇索引（如 InnoDB）的物理存储顺序，增加磁盘 I/O。</li>
<li class="">范围查询和排序效率低下，性能低下。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="uuidv7-的关键突破时间有序性架构设计">UUIDv7 的关键突破：时间有序性架构设计<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#uuidv7-%E7%9A%84%E5%85%B3%E9%94%AE%E7%AA%81%E7%A0%B4%E6%97%B6%E9%97%B4%E6%9C%89%E5%BA%8F%E6%80%A7%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>UUIDv7 通过在 UUID 的高位部分引入时间戳来解决生成 UUID 完全随机的问题，使新生成的 UUID 能够按照创建时间自然排序。这样，B 树索引可以像自增整数一样进行顺序插入，同时仍然保持 UUID 的全局唯一性和分布式生成优势。</p>
<p>该特性使 UUIDv7 作为主键具备以下突出优势：</p>
<ul>
<li class="">严格按照创建时间先后顺序递增。</li>
<li class="">减少索引碎片。</li>
<li class="">提高缓存命中率。</li>
<li class="">适合高并发插入和高效查询的场景。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="uuidv7-的结构设计">UUIDv7 的结构设计<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#uuidv7-%E7%9A%84%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250926-uuidv7-5ddf263b41da1fb9be96b0f53d963b16.png" width="1093" height="245" class="img_ev3q"></p>
<table><thead><tr><th>字段</th><th>位数</th><th>说明</th></tr></thead><tbody><tr><td>毫秒级 Unix 时间戳</td><td>48 位</td><td>Unix 时间戳（毫秒）</td></tr><tr><td>亚毫秒级时间戳分数（用于额外排序）</td><td>12 位</td><td>时间戳的微秒精度扩展</td></tr><tr><td>随机数</td><td>62 位</td><td>随机数或计数器</td></tr><tr><td>版本号</td><td>4 位</td><td>固定为 0111（v7）</td></tr><tr><td>变体</td><td>2 位</td><td>固定为 10（RFC 4122）</td></tr></tbody></table>
<p><strong>设计关键点解析：</strong></p>
<ul>
<li class=""><strong>高精度时间前缀(48 位):</strong> 精确到毫秒的 Unix 时间戳，确保 ID 严格按时间递增（需 NTP 时钟同步）。</li>
<li class=""><strong>尾部随机位(62 位):</strong> 保证分布式唯一性，避免 v1 版本的 MAC 地址泄漏风险。</li>
</ul>
<p><strong>有序性如何解决性能问题？</strong></p>
<ul>
<li class=""><strong>B-Tree 索引优化:</strong> 新生成的 UUIDv7 总是大于之前的值，因此被追加到索引尾部，避免中间节点分裂。</li>
<li class=""><strong>缓冲池友好:</strong> 顺序写入使新记录集中在少数数据页。当页写满时，数据库只需分配新页追加，减少旧页淘汰与磁盘 I/O。</li>
<li class=""><strong>范围查询加速:</strong> 时间有序性使 WHERE id &gt; '2025-06-01' 可转化为时间戳范围过滤，大幅降低扫描范围。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="如何在-postgresql18-中应用-uuidv7">如何在 PostgreSQL18 中应用 UUIDv7<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%A6%82%E4%BD%95%E5%9C%A8-postgresql18-%E4%B8%AD%E5%BA%94%E7%94%A8-uuidv7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 引入了多个新函数来支持 UUIDv7，方便生成、操作和提取 UUID 信息。</p>
<ol>
<li class=""><code>uuidv7()</code>函数：用于生成新的 UUIDv7 值</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 使用当前时间戳生成 UUIDv7</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 输出示例: 0197f96c-b278-7f64-a32f-dae3cabe1ff0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 生成 1 小时前的 UUIDv7</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">INTERVAL</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'-1 hour'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 生成 30 分钟后的 UUIDv7</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">INTERVAL</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'30 minutes'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<ol start="2">
<li class=""><code>uuidv4()</code>函数：作为已有函数 <code>gen_random_uuid()</code> 的别名 ，便于和 uuidv7 一起使用</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 两者等价</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> gen_random_uuid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuidv4</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<ol start="3">
<li class=""><code>uuid_extract_timestamp()</code>函数 : 该函数现在支持 UUIDv7（原本只支持 UUIDv1）</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 从 UUIDv7 提取时间戳</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuid_extract_timestamp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 示例输出: 2025-09-18 12:20:49.409+00</span><br></span></code></pre></div></div>
<ol start="4">
<li class=""><code>uuid_extract_version()</code>函数：用于检测 UUID 的版本：</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 检查 UUID 版本</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuid_extract_version</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">-- 返回 7</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> uuid_extract_version</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">uuidv4</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">-- 返回 4</span><br></span></code></pre></div></div>
<p>PostgreSQL 数据库中使用 UUIDv7 作为主键：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">--创建带 UUIDv7 主键的表</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> users </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id UUID </span><span class="token keyword" style="color:#00009f">PRIMARY</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">KEY</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    username </span><span class="token keyword" style="color:#00009f">VARCHAR</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">UNIQUE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    email </span><span class="token keyword" style="color:#00009f">VARCHAR</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    created_at </span><span class="token keyword" style="color:#00009f">TIMESTAMP</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WITH</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TIME</span><span class="token plain"> ZONE </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">CURRENT_TIMESTAMP</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>这样，每条新记录的 <code>id</code> 都会自动分配一个按时间戳排序的 UUID。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">--插入数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> users </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">username</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'alice'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'alice@example.com'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> users </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">username</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'bob'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'bob@example.com'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 按 UUID 时间顺序查看</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> username</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> uuid_extract_timestamp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> uuid_timestamp</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> users</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">ORDER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="性能优势">性能优势：<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%80%A7%E8%83%BD%E4%BC%98%E5%8A%BF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">UUIDv7 的时间戳顺序能显著减少页分裂和缓存失效，有效提升 B 树索引效率。</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">--创建性能测试表</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> performance_test </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id_v4 UUID </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> uuidv4</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id_v7 UUID </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> uuidv7</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">data</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TEXT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'sample data'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">--使用UUIDv7作为索引</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INDEX</span><span class="token plain"> idx_v4 </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> performance_test </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id_v4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INDEX</span><span class="token plain"> idx_v7 </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> performance_test </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id_v7</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>批量插入后，你可以用 <code>pg_statio_user_indexes</code> 查看索引命中情况，UUIDv7 通常表现更优。</p>
<ol start="2">
<li class="">UUIDv7 自带时间排序，大部分场景下显著提升排序性能。</li>
</ol>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 利用 UUIDv7 自然排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> id_v7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">data</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> performance_test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">ORDER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> id_v7</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">LIMIT</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>相比 UUIDv4 的随机顺序，UUIDv7 查询结果按创建顺序返回，更直观。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="uuidv7-最佳实践">UUIDv7 最佳实践<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#uuidv7-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250926-uuidv7-2-5dc7700627ddfee6c6ae0d2e1c26eabe.png" width="1062" height="389" class="img_ev3q"></p>
<p>适合使用 UUIDv7 的场景：</p>
<ul>
<li class="">
<p><strong>多租户应用</strong>：可用 UUIDv7 做主键，并为 <code>(tenant_id, id)</code> 创建复合索引，既保持唯一性又能按时间排序。</p>
</li>
<li class="">
<p><strong>分布式系统</strong>：多个服务可独立生成 UUIDv7，并且在全局范围内仍能保持时间顺序。</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="限制与注意事项">限制与注意事项<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E9%99%90%E5%88%B6%E4%B8%8E%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ul>
<li class=""><strong>依赖系统时钟</strong>：需启用 NTP 等时间同步机制，避免时钟漂移。</li>
<li class=""><strong>时间戳精度</strong>：UUIDv7 以毫秒为单位，在同一毫秒内生成多个 UUID，顺序可能无法完全反映真实创建顺序，但仍保持唯一性。</li>
<li class=""><strong>迁移规划</strong>：从 UUIDv4 迁移到 UUIDv7 时，需要检查应用逻辑、索引和外部依赖。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结-3">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93-3" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 对 UUIDv7 的支持，解决了 UUID 作为主键的性能瓶颈。UUIDv7 在保持全局唯一性的同时，具备类似自增整数的顺序性，使 B 树插入更高效，查询更快。</p>
<p>对于需要分布式、高并发和高性能的现代应用，UUIDv7 提供了一种兼顾唯一性和性能的实用解决方案。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五explain-增强直观呈现执行细节">五、EXPLAIN 增强：直观呈现执行细节<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BA%94explain-%E5%A2%9E%E5%BC%BA%E7%9B%B4%E8%A7%82%E5%91%88%E7%8E%B0%E6%89%A7%E8%A1%8C%E7%BB%86%E8%8A%82" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>PostgreSQL 18 对 EXPLAIN 命令进行了重大升级，通过提供更丰富、更直观的执行计划信息，让数据库开发者和 DBA 能够更加轻松地进行查询性能分析与优化。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="自动缓冲区分析">自动缓冲区分析<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%87%AA%E5%8A%A8%E7%BC%93%E5%86%B2%E5%8C%BA%E5%88%86%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>EXPLAIN ANALYZE 现在默认包含 BUFFER 统计信息，无需手动添加 BUFFERS 选项：</p>
<ul>
<li class=""><strong>共享命中(Shared Hits)</strong>：显示从缓存中读取的数据块数量，反映内存使用效率。</li>
<li class=""><strong>共享读取(Shared Reads)</strong>：标识必须从磁盘读取的数据块，帮助识别 I/O 瓶颈。</li>
<li class=""><strong>共享脏块(Shared Dirtied)</strong>：针对数据修改操作，显示被更改的块数量。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="精细化索引监控">精细化索引监控<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E7%B2%BE%E7%BB%86%E5%8C%96%E7%B4%A2%E5%BC%95%E7%9B%91%E6%8E%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>新增索引扫描次数统计，让开发者能够精确了解索引使用效率：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 示例输出显示索引使用情况</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Scan </span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> orders_pkey </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> orders</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Searches: </span><span class="token number" style="color:#36acaa">1</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">-- 明确显示索引查找次数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="增强的统计信息">增强的统计信息<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%A2%9E%E5%BC%BA%E7%9A%84%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ul>
<li class="">支持小数行（ fractional row counts），提供更精确的行数估计。</li>
<li class="">为 Material、Window Aggregate、CTE 节点输出内存和磁盘使用详情。</li>
<li class="">在窗口函数中显示详细的参数信息。</li>
<li class="">为 Parallel Bitmap Heap Scan 显示 worker 缓存统计。</li>
<li class="">输出禁用节点。</li>
<li class="">输出 WAL 缓冲区信息。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="基础查询分析">基础查询分析<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E5%88%86%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">-- 创建测试表</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> orders </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    order_id </span><span class="token keyword" style="color:#00009f">SERIAL</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">PRIMARY</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">KEY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    customer_id </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    order_date </span><span class="token keyword" style="color:#00009f">DATE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    total_amount </span><span class="token keyword" style="color:#00009f">DECIMAL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INDEX</span><span class="token plain"> idx_orders_customer_id </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> orders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">customer_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 插入测试数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> orders </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">customer_id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> order_date</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> total_amount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">CURRENT_DATE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">365</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">950</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">decimal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> generate_series</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> n</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-- 查看增强的执行计划</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">EXPLAIN</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ANALYZE</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">,</span><span class="token function" style="color:#d73a49">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">total_amount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">OVER</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">PARTITION</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> customer_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> orders </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> order_id</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token number" style="color:#36acaa">49900</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>执行计划：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">QUERY </span><span class="token keyword" style="color:#00009f">PLAN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">----------------------------------------------------------------------------------------------------------------------------------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> WindowAgg  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">13.46</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.15</span><span class="token number" style="color:#36acaa">.04</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">99</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.630</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.0</span><span class="token number" style="color:#36acaa">.745</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">100.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Window: w1 </span><span class="token keyword" style="color:#00009f">AS</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">PARTITION</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> customer_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Storage: Memory  Maximum Storage: </span><span class="token number" style="color:#36acaa">17</span><span class="token plain">kB</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  Sort  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">13.30</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.13</span><span class="token number" style="color:#36acaa">.55</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">99</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">18</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.307</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.0</span><span class="token number" style="color:#36acaa">.333</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">100.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Sort </span><span class="token keyword" style="color:#00009f">Key</span><span class="token plain">: customer_id</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Sort Method: quicksort  Memory: </span><span class="token number" style="color:#36acaa">28</span><span class="token plain">kB</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Scan </span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> orders_pkey </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> orders  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.29</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.10</span><span class="token number" style="color:#36acaa">.02</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">99</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">18</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.089</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.0</span><span class="token number" style="color:#36acaa">.174</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">100.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Cond: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">order_id </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">49900</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Searches: </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">64</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">22</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">2.080</span><span class="token plain"> ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">1.343</span><span class="token plain"> ms</span><br></span></code></pre></div></div>
<p>执行计划输出洞察：</p>
<ul>
<li class="">缓冲区使用情况（缓存命中 vs 磁盘读取）：生成执行计划时从缓存中访问了 64 个共享缓冲区，从磁盘中读取了 22 个缓冲区，执行时从缓冲区访问了 5 个共享缓冲区，从磁盘读取了 2 个缓冲区。</li>
<li class="">索引效率统计：执行了 1 次 orders_pkey 索引扫描，并从缓存中访问了 2 个共享缓冲区，清晰地显示了索引的使用效率。</li>
<li class="">窗口函数内存使用详情：使用的 17kB 磁盘空间。</li>
<li class="">精确的行统计信息。</li>
<li class="">窗口函数的详细参数。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="wal-日志分析">WAL 日志分析<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#wal-%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">EXPLAIN</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">ANALYZE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> WAL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> orders </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">customer_id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> order_date</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> total_amount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">CURRENT_DATE</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">365</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">950</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">decimal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> generate_series</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> n</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>执行计划：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">QUERY </span><span class="token keyword" style="color:#00009f">PLAN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">---------------------------------------------------------------------------------------------------------------------------------------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Insert</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> orders  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.2000</span><span class="token number" style="color:#36acaa">.00</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">767.116</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.767</span><span class="token number" style="color:#36acaa">.118</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">299156</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">read</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> dirtied</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">500</span><span class="token plain"> written</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">501</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   WAL: records</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">152158</span><span class="token plain"> bytes</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">10427828</span><span class="token plain"> buffers </span><span class="token keyword" style="color:#00009f">full</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">139</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  Subquery Scan </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"*SELECT*"</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.2000</span><span class="token number" style="color:#36acaa">.00</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50000</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">28</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5.742</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.336</span><span class="token number" style="color:#36acaa">.699</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50000.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50013</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         WAL: records</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1516</span><span class="token plain"> bytes</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">150084</span><span class="token plain"> buffers </span><span class="token keyword" style="color:#00009f">full</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  </span><span class="token keyword" style="color:#00009f">Function</span><span class="token plain"> Scan </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> generate_series n  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.1750</span><span class="token number" style="color:#36acaa">.00</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50000</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">24</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5.460</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.227</span><span class="token number" style="color:#36acaa">.650</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">50000.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">0.114</span><span class="token plain"> ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">767.179</span><span class="token plain"> ms</span><br></span></code></pre></div></div>
<p>WAL 统计：</p>
<ul>
<li class="">监控写入负载的日志生成量：WAL 缓冲区生成 1516 条日志，共 150084 个字节的数据。</li>
<li class="">诊断写入性能瓶颈：缓冲区被写满了 2 次。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="并行查询优化">并行查询优化<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B9%B6%E8%A1%8C%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">EXPLAIN</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">ANALYZE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> orders </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> customer_id </span><span class="token operator" style="color:#393A34">IN</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>执行计划：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">QUERY </span><span class="token keyword" style="color:#00009f">PLAN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">-------------------------------------------------------------------------------------------------------------------------------------------------------</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Gather  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2752.40</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.10357</span><span class="token number" style="color:#36acaa">.99</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">327855</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">18</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">22.375</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.121</span><span class="token number" style="color:#36acaa">.296</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">330000.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Planned: </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Workers Launched: </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3810</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  Parallel Bitmap Heap Scan </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> orders  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2751.40</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.10029</span><span class="token number" style="color:#36acaa">.13</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">136606</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">18</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">12.868</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.88</span><span class="token number" style="color:#36acaa">.329</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">110000.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Recheck Cond: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">customer_id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ANY</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'{1,2,3,4,5,6}'</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">integer</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token keyword" style="color:#00009f">Rows</span><span class="token plain"> Removed </span><span class="token keyword" style="color:#00009f">by</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Recheck: </span><span class="token number" style="color:#36acaa">53967</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Heap Blocks: exact</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">170</span><span class="token plain"> lossy</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">566</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3810</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Worker </span><span class="token number" style="color:#36acaa">0</span><span class="token plain">:  Heap Blocks: exact</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">387</span><span class="token plain"> lossy</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">957</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         Worker </span><span class="token number" style="color:#36acaa">1</span><span class="token plain">:  Heap Blocks: exact</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">369</span><span class="token plain"> lossy</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1055</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">  Bitmap </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Scan </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> idx_orders_customer_id  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cost</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.00</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.2669</span><span class="token number" style="color:#36acaa">.44</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">327855</span><span class="token plain"> width</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actual </span><span class="token keyword" style="color:#00009f">time</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">21.219</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">.21</span><span class="token number" style="color:#36acaa">.220</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rows</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">330000.00</span><span class="token plain"> loops</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Cond: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">customer_id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ANY</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'{1,2,3,4,5,6}'</span><span class="token plain">::</span><span class="token keyword" style="color:#00009f">integer</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token keyword" style="color:#00009f">Index</span><span class="token plain"> Searches: </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">266</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Buffers: shared hit</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">30</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Planning </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">0.510</span><span class="token plain"> ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Execution </span><span class="token keyword" style="color:#00009f">Time</span><span class="token plain">: </span><span class="token number" style="color:#36acaa">158.523</span><span class="token plain"> ms</span><br></span></code></pre></div></div>
<p>并行执行效率洞察：</p>
<ul>
<li class="">每个工作进程的缓存统计详情：worker 0 命中 387 个精确块和 957 个有损块，worker 1 命中 369 个精确块和 1055 个有损块。</li>
<li class="">精确块与有损块分析：出现有损块说明可能 work_mem 太小导致 bitmap 无法精准定位元组。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="技术优势与价值">技术优势与价值<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%8A%80%E6%9C%AF%E4%BC%98%E5%8A%BF%E4%B8%8E%E4%BB%B7%E5%80%BC" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="即时性能诊断">即时性能诊断<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%8D%B3%E6%97%B6%E6%80%A7%E8%83%BD%E8%AF%8A%E6%96%AD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<ul>
<li class=""><strong>降低门槛</strong>：自动化的缓冲区统计让初学者快速识别 I/O 问题。</li>
<li class=""><strong>深度洞察</strong>：为专家级用户提供更细粒度的性能数据。</li>
<li class=""><strong>全面覆盖</strong>：单条命令获取执行计划、缓存使用、索引效率等多维信息。</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="优化指导">优化指导<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BC%98%E5%8C%96%E6%8C%87%E5%AF%BC" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<ul>
<li class=""><strong>索引优化</strong>：通过精确的索引使用统计，避免过度索引或索引不足。</li>
<li class=""><strong>内存调优</strong>：根据有损块出现频率指导 work_mem 参数调整</li>
<li class=""><strong>查询重写</strong>：基于详细的执行成本数据优化 SQL 语句结构</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="功能未来展望">功能未来展望<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%8A%9F%E8%83%BD%E6%9C%AA%E6%9D%A5%E5%B1%95%E6%9C%9B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>尽管 PostgreSQL 18 的 EXPLAIN 增强带来了显著改进，但仍有一些方面可以进一步完善：</p>
<ol>
<li class=""><strong>输出可读性</strong>：随着信息量的增加，输出变得更加复杂，可能需要更好的格式化或可视化工具支持</li>
<li class=""><strong>历史对比</strong>：缺乏直接与历史执行计划对比的内置机制，使得性能回归分析仍需依赖外部工具</li>
<li class=""><strong>阈值警报</strong>：没有内置机制对异常值（如异常高的缓冲区读取）发出警告，需要手动分析</li>
<li class=""><strong>执行计划可视化</strong>：文本形式的输出在复杂查询中仍难以直观理解，需要第三方工具补充</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结-4">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93-4" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 的 EXPLAIN 增强代表了数据库可观测性的重大进步。通过自动化收集关键性能指标并提供更深入的执行洞察，它显著降低了查询优化的门槛，同时为经验丰富的 DBA 提供了更强大的分析能力。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六oauth-20-认证支持筑牢数据防护壁垒">六、OAuth 2.0 认证支持：筑牢数据防护壁垒<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%85%ADoauth-20-%E8%AE%A4%E8%AF%81%E6%94%AF%E6%8C%81%E7%AD%91%E7%89%A2%E6%95%B0%E6%8D%AE%E9%98%B2%E6%8A%A4%E5%A3%81%E5%9E%92" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在安全方面，IvorySQL 致力于加入多种国密认证功能来保障数据安全。而这次 PostgreSQL18 在身份认证方面继续加强，引入对 OAuth 2 的支持。这是一种开放标准的授权协议，用于授权一个应用程序或服务访问用户在另一个应用程序中的资源，而无需提供用户名和密码。</p>
<p>该特性主要包含以下几个核心要素：</p>
<ul>
<li class=""><strong>OAuth2 验证器框架</strong>：提供了一个可扩展的框架，使 PostgreSQL 能够与 OAuth 2.0 提供程序集成。PostgreSQL 本身不实现具体的令牌验证算法（如 JWT 验证），而是将这项工作委托给一个外部共享库 (<code>*.so</code> 文件)。</li>
<li class=""><strong>客户端认证支持</strong>：libpq（PostgreSQL 的 C 客户端库）现在支持 OAuth 2.0 认证流程。</li>
<li class=""><strong>自定义验证逻辑</strong>：通过回调机制允许实现自定义的令牌验证和用户映射逻辑。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置-oauth-认证方式">配置 OAuth 认证方式<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E9%85%8D%E7%BD%AE-oauth-%E8%AE%A4%E8%AF%81%E6%96%B9%EF%BF%BD%EF%BF%BD%E5%BC%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="服务端配置">服务端配置<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%9C%8D%E5%8A%A1%E7%AB%AF%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<ol>
<li class="">
<p>选择 OAuth 认证的方式与瀚高数据库选择国密认证的方式类似，需要通过在 pg_hba.conf 文件中指定 METHOD 为 oauth，开启 OAuth 认证。</p>
<p>同时 OPTIONS 必须指定 issuer 和 scope 参数，除此之外还有几个可选参数：validator、map、delegate_ident_mapping，以下是一个最简配置示例：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">local all test oauth issuer="http://127.0.0.1:9000" scope="openid postgre"</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>指定外部 OAuth 验证器，在 postgresql.conf 文件中配置新提供的 oauth_validator_libraries 参数，配置内容为 OAuth 验证器提供的库文件。</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端配置">客户端配置<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>客户端在连接时需要指定以下连接参数从而实现连接：</p>
<ul>
<li class="">oauth_issuer：必要参数，HTTPS URL，是授权服务器的颁发者标识符。</li>
<li class="">oauth_client_id：必要参数，由授权服务器颁发的 OAuth 2.0 客户端标识符。</li>
<li class="">oauth_client_secret：可选参数，访问 OAuth 授权服务器时要使用的客户端密码。</li>
<li class="">oauth_scope：可选参数，发送到授权服务器的访问请求的范围，指定为 OAuth 范围标识符的空格分隔列表。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="认证实现原理">认证实现原理<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E8%AE%A4%E8%AF%81%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>oauth 整体认证流程大致如下图所示：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250926-oauth-97f62144108afc05d4145c50d8b8cec1.png" width="766" height="931" class="img_ev3q"></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端libpq">客户端（libpq）<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%AE%A2%E6%88%B7%E7%AB%AFlibpq" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>PostgreSQL 实现了一个<strong>非阻塞的、基于状态机的异步网络客户端</strong>。状态机包含 <code>OAUTH_STEP_INIT</code>、<code>OAUTH_STEP_DISCOVERY</code>、<code>OAUTH_STEP_DEVICE_AUTHORIZATION</code>、<code>OAUTH_STEP_TOKEN_REQUEST</code>、<code>OAUTH_STEP_WAIT_INTERVAL</code> 这几个状态。其核心原理包含以下几个部分：</p>
<ul>
<li class=""><strong>DISCOVERY</strong>：客户端从用户请求中获取授权服务器元信息。</li>
<li class=""><strong>DEVICE_AUTHORIZATION</strong>：客户端向授权服务器发送请求，授权服务器返回 device_code 和 verification_uri。客户端输出信息"Visit xxxxxx and enter the code: xxxxxx"，提示用户进行操作。</li>
<li class=""><strong>TOKEN_REQUEST 和 WAIT_INTERVAL</strong>：轮询访问授权服务器，直到用户完成授权，授权服务器返回 access_token 给客户端。</li>
<li class="">将获取到的 <code>access_token</code> 设置到连接对象中。<code>libpq</code> 会将它作为密码发送给 PostgreSQL 服务器，服务器端的 OAuth 验证器会负责校验这个令牌。</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="服务端">服务端<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%9C%8D%E5%8A%A1%E7%AB%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>以下 PostgreSQL 服务端处理 OAuth 认证流程，同样通过状态机实现，但要比客户端简单得多，总共分为 <code>OAUTH_STATE_INIT</code>、<code>OAUTH_STATE_ERROR</code>、<code>OAUTH_STATE_FINISHED</code> 三个状态。以下是核心步骤：</p>
<ul>
<li class="">首先解析客户端发送的消息，该消息格式遵循 RFC 7628 第 3.1 节部分。</li>
<li class="">从客户端消息中提取出纯粹的 Bearer Token，并验证其格式（是否为合法的 Base64 字符串）。</li>
<li class="">将提取出的令牌传递给验证器模块进行实质性的验证。<!-- -->
<ul>
<li class="">验证成功：状态转为 <code>OAUTH_STATE_FINISHED</code>，返回 <code>PG_SASL_EXCHANGE_SUCCESS</code>。进行建立连接的后续操作。</li>
<li class="">验证失败：生成一个符合 RFC 7628 第 3.2.2 节的 JSON 错误响应，告知客户端所需的 <code>scope</code> 和到哪里获取令牌。状态转为 <code>OAUTH_STATE_ERROR</code>，并返回 <code>PG_SASL_EXCHANGE_CONTINUE</code>，等待客户端发送最终的 <code>KVSEP</code> 来结束失败的握手。</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="外部验证器">外部验证器<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%A4%96%E9%83%A8%E9%AA%8C%E8%AF%81%E5%99%A8" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h4>
<p>外部验证器通常需要处理以下事项：</p>
<ul>
<li class="">令牌验证：可以通过在线验证和本地验证两种方式，由验证器自行决定。在线验证下验证器通常将令牌发送到授权服务器专门的 <code>Introspection Endpoint</code>，授权服务器会返回一个 JSON 响应，告知令牌是否有效。本地验证则需要验证器内部实现一套验证流程，本地验证令牌的签名和有效期。本地验证的好处在于能够快速响应，但缺点是无法实时检测令牌撤销。</li>
<li class="">身份映射：在验证通过后，验证器需要提取令牌中的唯一用户标识，并转换为数据库可理解的身份标识，也就是数据库用户。</li>
<li class="">连接决策：如果令牌处于有效期并且存在相应的数据库用户映射关系，则以该用户的身份创建会话连接。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="优缺点剖析">优缺点剖析<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E4%BC%98%E7%BC%BA%E7%82%B9%E5%89%96%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p><strong>优点：</strong></p>
<ol>
<li class="">OAuth2 提供了现代、标准化的身份验证机制，提高了安全性。通过 OAuth2 认证，规避了传统密码认证在数据传输过程中暴露密码导致的安全风险。</li>
<li class="">简化了数据库用户管理，支持统一的身份策略和访问控制，提高了管理效率。</li>
</ol>
<p><strong>缺点：</strong></p>
<ol>
<li class="">相较于传统的密码认证，实现更加复杂，需要额外的配置和维护工作，包括 OAuth2 提供程序的设置和管理，提高了运维的复杂度。比如瀚高数据库的国密认证功能，同样在保障口令安全的同时仅需要通过非常简单的配置即可使用。</li>
<li class="">依赖于外部 OAuth 提供程序的可用性和可靠性，若 OAuth 提供程序出现问题，可能会影响数据库访问。</li>
<li class="">每次连接可能需要额外的网络请求来验证令牌，可能会增加连接建立的时间，特别是在高并发场景下。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结-5">小结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E5%B0%8F%E7%BB%93-5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>PostgreSQL 18 引入的 OAuth2 支持是一个重要的安全增强功能，它允许组织使用现代的身份验证机制来保护数据库访问。通过提供灵活的验证器框架和回调机制，PostgreSQL 18 可以适应各种 OAuth2 部署场景和业务需求。</p>
<p>虽然 OAuth2 认证增加了系统的复杂性，但它提供了显著的安全优势，特别是在集中式身份管理和单点登录方面。对于希望采用现代安全最佳实践的组织来说，这是一个值得考虑的新功能。OAuth 认证并不与已有的认证方式冲突，在不希望进行繁琐的配置时，仍然可以选择类似于瀚高数据库提供的国密认证等方式。</p>
<p>在实施 OAuth2 认证时，组织应该仔细评估其需求、现有基础设施和技术能力，以确保成功部署和运维。同时应该考虑到性能、可用性和兼容性等因素，以提供最佳的用户体验和系统可靠性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://ivorysql.org/zh-cn/blog/analysis-of-pg-18-key-new-features#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>PostgreSQL 18 凭借六大核心特性实现了性能、功能与安全性的全方位升级：</p>
<ul>
<li class="">异步 I/O 突破了同步阻塞瓶颈，提升读取密集型场景的吞吐量。</li>
<li class="">跳跃式扫描让多列 B 树索引在非前导列查询中发挥高效作用。</li>
<li class="">虚拟生成列在存储与计算间找到了灵活平衡，优化了开发体验。</li>
<li class="">UUIDv7 解决了传统 UUID 无序性带来的性能痛点，兼顾唯一性与顺序性。</li>
<li class="">EXPLAIN 增强为查询优化提供了更直观、细致的执行洞察。</li>
<li class="">OAuth 2.0 认证则为数据安全筑牢了现代防护屏障。</li>
</ul>
<p>这些特性不仅满足了当前数据库在高性能、高并发、易开发、强安全等方面的需求，也为未来在跨平台适配、功能扩展等方向奠定了坚实基础，进一步巩固了 PostgreSQL 在开源数据库领域的领先地位，为各类应用场景提供了更强大、更灵活的技术支撑。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="UUIDv7" term="UUIDv7"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="I/O" term="I/O"/>
        <category label="OAuth" term="OAuth"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL-WASM：免安装的数据库探索之旅]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-wasm</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-wasm"/>
        <updated>2025-05-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[简介]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="简介">简介<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>为了降低社区用户的使用门槛，提升使用体验，IvorySQL 社区特别推出了 IvorySQL-WASM 项目，帮助用户快速在线 Demo。</p>
<p>IvorySQL-WASM 基于开源的 Postgres-WASM 框架开发。它允许用户直接在网页浏览器中体验 IvorySQL，无需本地安装或复杂部署。通过结合 WebAssembly 和虚拟化技术，IvorySQL-WASM 提供了一种简单、轻量且易于访问的方式，让开发者、测试人员和数据库爱好者能够轻松探索 IvorySQL 的强大功能。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="技术分析">技术分析<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL-WASM 核心技术：</p>
<ul>
<li class="">
<p><strong>V86</strong>：x86 模拟器，用于模拟虚拟操作系统所需的硬件环境，包括 CPU、内存、VGA、BIOS 和串口等组件。</p>
</li>
<li class="">
<p><strong>BuildRoot</strong>：用于构建在 V86 上运行的精简 Linux 系统镜像，集成 IvorySQL 4.4 服务及其稳定运行环境。</p>
</li>
<li class="">
<p><strong>WebAssembly (WASM)</strong>：一种低级的类汇编二进制指令格式，通过 <a href="https://emscripten.org/" target="_blank" rel="noopener noreferrer" title="Emscripten" class="">Emscripten</a> 等工具将 C/C++ 代码编译为 WASM 模块，从而将现有的 C 库生态系统移植到 Web 平台。WASM 具有紧凑的二进制格式和接近原生的运行性能，是 IvorySQL-WASM 项目运行数据库服务的核心技术。</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="快速部署">快速部署<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>开发者若想在本地部署 IvorySQL-WASM 项目，可参考以下步骤：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="linux-环境">Linux 环境<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#linux-%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">准备运行依赖工具：Node.js 和 npm。</li>
<li class="">克隆项目：<code>git clone git@github.com:IvorySQL/ivorysql-wasm.git</code></li>
<li class="">进入 <code>package/runtime</code> 目录，启动 http 服务：<code>npx serve</code></li>
<li class="">在浏览器访问：<code>http://server_ip:3000</code></li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="windows-环境">Windows 环境<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#windows-%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">下载并安装 <a href="https://nodejs.org/dist/v22.15.0/node-v22.15.0-x64.msi" target="_blank" rel="noopener noreferrer" title="Node.js" class="">Node.js</a>。</li>
<li class="">在 PowerShell 的相应目录下执行 <code>npx.cmd serve</code>，启动 http 服务器。</li>
</ol>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/w-1-5a8c60395b5b08e5d9435b0cd67c747b.png" width="692" height="303" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="体验">体验<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E4%BD%93%E9%AA%8C" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>通过访问 <code>http://192.168.31.186:3000/</code>，用户可以进行 IvorySQL 在线体验，例如创建 <code>t1</code> 表格并列出表格。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/w-2-73fbcfe398872626e3e16b39767cf183.png" width="1874" height="772" class="img_ev3q"></p>
<p>运行精简 Linux 虚拟机时，浏览器需先下载相关镜像系统文件（约 35MB）和状态快照（15MB）。因此，首次打开页面可能需要等待几秒至二十几秒，具体时长取决于 http 服务位于内网还是外网环境。状态快照用于快速加载预配置的数据库。</p>
<p>通过任务管理器可以观察到，IvorySQL 在浏览器中的运行对 CPU 和内存的占用较为理想。</p>
<p><img decoding="async" loading="lazy" alt="img" src="data:image/png;base64,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" width="958" height="65" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="注意事项">注意事项<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">
<p>数据库存储在内存中，刷新页面后数据库将被清空，系统恢复到初始状态。</p>
</li>
<li class="">
<p>IvorySQL 采用双端口设计，默认连接端口为 1521。若需从 5432 端口登录，请在 shell 终端退出 psql，然后执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">psql -U postgres -p 5432 -d postgres</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/w-4-05b8390bab87d0d912f731e29bf50a31.png" width="803" height="263" class="img_ev3q"></p>
</li>
<li class="">
<p>如果用户想保存当前的数据库怎么办？请点击“Save state to file”，浏览器会自动产生并下载 <code>v86state.bin</code> 文件；再次使用保持的数据库时，点击页面“Restore from file”，上传 <code>v86state.bin</code> 文件即可。</p>
</li>
<li class="">
<p>V86 系统最小内存配置 128 MB，即当前为配置。</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="开发者可以改动源码满足实际需求">开发者可以改动源码，满足实际需求。<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E5%BC%80%E5%8F%91%E8%80%85%E5%8F%AF%E4%BB%A5%E6%94%B9%E5%8A%A8%E6%BA%90%E7%A0%81%E6%BB%A1%E8%B6%B3%E5%AE%9E%E9%99%85%E9%9C%80%E6%B1%82" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">BuildRoot 部分请参考 <code>package/buildroot/README.md</code></li>
<li class="">V86 部分请参考<a href="https://github.com/copy/v86/releases/tag/latest" target="_blank" rel="noopener noreferrer" class="">https://github.com/copy/v86/releases/tag/latest</a></li>
<li class="">Web 页面部分请参考 <code>package/runtime/README.md</code></li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="社区版即将发布">社区版即将发布<a href="https://ivorysql.org/zh-cn/blog/ivorysql-wasm#%E7%A4%BE%E5%8C%BA%E7%89%88%E5%8D%B3%E5%B0%86%E5%8F%91%E5%B8%83" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL-WASM 社区版将会伴随 IvorySQL 4.5 一起发布，详情请关注 <a href="https://www.ivorysql.org/zh-cn/" target="_blank" rel="noopener noreferrer" class="">IvorySQL 官网</a>信息。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="WasmEdge" term="WasmEdge"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 增量备份与合并增量备份功能解析]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features"/>
        <updated>2025-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[1. 概述]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-概述">1. 概述<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#1-%E6%A6%82%E8%BF%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL v4 引入了块级增量备份和增量备份合并功能，旨在优化数据库备份与恢复流程。通过 <code>pg_basebackup</code> 工具支持增量备份，显著降低了存储需求和备份时间。同时，<code>pg_combinebackup</code> 工具能够将多个增量备份合并为单个完整备份，提升了数据恢复的灵活性和效率。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-特性介绍">2. 特性介绍<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#2-%E7%89%B9%E6%80%A7%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL 的增量备份通过记录每个 checkpoint 周期内的数据变更，确保仅备份自上次备份以来发生变化的数据块。这种机制不仅减少了所需的存储空间，也缩短了备份过程中的 I/O 操作时间。此外，<code>pg_combinebackup</code> 工具支持将多个增量备份合并为一个完整备份，使得在数据恢复时不再需要逐个应用增量备份，大大简化了恢复流程。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-1-8f4120529e6e3b72a1eb39447241ed2e.png" width="1267" height="558" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-启用增量备份特性">2.1 启用增量备份特性<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#21-%E5%90%AF%E7%94%A8%E5%A2%9E%E9%87%8F%E5%A4%87%E4%BB%BD%E7%89%B9%E6%80%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>为启用增量备份功能，首先需要在数据库中配置相关参数并重新加载配置文件：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">ALTER</span><span class="token plain"> SYSTEM </span><span class="token keyword" style="color:#00009f">SET</span><span class="token plain"> summarize_wal </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ON</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_reload_conf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>接着，创建测试表并插入初始数据，以便后续进行备份操作：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t </span><span class="token keyword" style="color:#00009f">INT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> sample_table </span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-2-ebb15bf5ff6e1a025f31ab176d56a71f.png" width="297" height="103" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-执行全量备份">2.2 执行全量备份<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#22-%E6%89%A7%E8%A1%8C%E5%85%A8%E9%87%8F%E5%A4%87%E4%BB%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>使用 <code>pg_basebackup</code> 工具执行全量备份，并生成包含 <code>backup_manifest</code> 的备份文件，以便后续增量备份的基础：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_basebackup -Fp -D /backup/\$(date +%Y-%m-%d*%H%M%S-FULL)</span><br></span></code></pre></div></div>
<p>此命令将全量备份数据保存至指定目录，并记录当前的备份状态。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-进行增量备份">2.3 进行增量备份<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#23-%E8%BF%9B%E8%A1%8C%E5%A2%9E%E9%87%8F%E5%A4%87%E4%BB%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>（1）在对数据进行修改后，执行增量备份以记录自上次全量备份或增量备份以来的变更。</p>
<p>修改表数据并执行第一次增量备份：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">UPDATE</span><span class="token plain"> sample_table </span><span class="token keyword" style="color:#00009f">SET</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-3-f6122485af0a5a07e2e015eccf77e216.png" width="291" height="138" class="img_ev3q"></p>
<p>执行增量备份：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_basebackup -Fp -D /backup/\$(date +%Y-%m-%d*%H%M%S-INCREMENTAL) -i /backup/2025-02-20_161530-FULL/backup_manifest</span><br></span></code></pre></div></div>
<p>（2）再次修改表数据并执行第二次增量备份。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">UPDATE</span><span class="token plain"> sample_table </span><span class="token keyword" style="color:#00009f">SET</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-4-3a56abb51193113ec5438b524ed93a9e.png" width="314" height="142" class="img_ev3q"></p>
<p>然后执行第二次增量备份：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_basebackup -Fp -D /backup/\$(date +%Y-%m-%d*%H%M%S-INCREMENTAL) -i /backup/2025-02-20_161808-INCREMENTAL/backup_manifest</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-5-7427bc75793302a6177d8145139b9c8b.png" width="599" height="105" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="24-合并增量备份">2.4 合并增量备份<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#24-%E5%90%88%E5%B9%B6%E5%A2%9E%E9%87%8F%E5%A4%87%E4%BB%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>合并全量备份和多个增量备份，创建新的完整备份，以便后续的恢复操作：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">cd /backup</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pg_combinebackup 2025-02-20_161530-FULL 2025-02-20_161808-INCREMENTAL 2025-02-20_162115-INCREMENTAL -o 2025-02-20_66666-FULL</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-6-5c830f7a20815ce3c1e0e6c1abd1d5a5.png" width="605" height="128" class="img_ev3q"></p>
<blockquote>
<p>注意事项：全量备份必须在参数列表的首位，增量备份需要按时间顺序排列，以确保数据恢复的完整性与一致性。</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="25-恢复合并后的备份">2.5 恢复合并后的备份<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#25-%E6%81%A2%E5%A4%8D%E5%90%88%E5%B9%B6%E5%90%8E%E7%9A%84%E5%A4%87%E4%BB%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>启动数据库并验证数据的完整性：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl </span><span class="token keyword" style="color:#00009f">start</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">D </span><span class="token operator" style="color:#393A34">/</span><span class="token keyword" style="color:#00009f">backup</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">2025</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">02</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20</span><span class="token plain">_66666</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">FULL</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">o </span><span class="token string" style="color:#e3116c">'-p 5435'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-7-fa0cc137940024161bb3c75547a3636d.png" width="1059" height="532" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="26-合并指定增量备份">2.6 合并指定增量备份<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#26-%E5%90%88%E5%B9%B6%E6%8C%87%E5%AE%9A%E5%A2%9E%E9%87%8F%E5%A4%87%E4%BB%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>如需恢复到特定的增量备份状态，可以选择合并到某个中间增量备份：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_combinebackup </span><span class="token number" style="color:#36acaa">2025</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">02</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20</span><span class="token plain">_161530</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">FULL</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2025</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">02</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20</span><span class="token plain">_161808</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">INCREMENTAL </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">o </span><span class="token number" style="color:#36acaa">2025</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">02</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20</span><span class="token plain">_77777</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">FULL</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-8-09c567f682acc20fe5cba35c19538d6e.png" width="594" height="140" class="img_ev3q"></p>
<p>然后启动数据库并验证数据：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl </span><span class="token keyword" style="color:#00009f">start</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">D </span><span class="token operator" style="color:#393A34">/</span><span class="token keyword" style="color:#00009f">backup</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">2025</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">02</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">20</span><span class="token plain">_77777</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">FULL</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">o </span><span class="token string" style="color:#e3116c">'-p 5436'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> sample_table</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250320-9-3b1553fe5925fcf96099b34bda2e6cb5.png" width="1049" height="536" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-注意事项">3. 注意事项<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#3-%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="备份顺序">备份顺序<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#%E5%A4%87%E4%BB%BD%E9%A1%BA%E5%BA%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>确保全量备份在合并命令的首位，增量备份按照时间顺序排列，以避免合并过程中的数据不一致性问题。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="增量备份存储管理">增量备份存储管理<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#%E5%A2%9E%E9%87%8F%E5%A4%87%E4%BB%BD%E5%AD%98%E5%82%A8%E7%AE%A1%E7%90%86" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>虽然增量备份减少了存储空间的需求，但恢复操作依赖于完整的增量备份链，任何增量备份的丢失将直接导致恢复失败。因此，建议定期检查和合并增量备份，以确保备份链的完整性和可靠性。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="性能监控">性能监控<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在执行增量备份和合并操作时，监控数据库的性能，确保操作对系统性能的影响在可接受范围内，避免在高负载时段进行备份操作。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-总结">4. 总结<a href="https://ivorysql.org/zh-cn/blog/ivorysql-incremental-backup-and-merge-features#4-%E6%80%BB%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL 提供的块级增量备份与 <code>pg_combinebackup</code> 工具显著提升了数据库的备份与恢复效率。通过只备份变更的数据块，增量备份在减小存储占用和缩短备份时间方面展现出卓越性能，而合并增量备份功能则简化了恢复流程，提升了操作的便捷性。</p>
<p>这些先进的特性使得 IvorySQL 成为大规模数据库和对数据恢复要求严格的环境的理想选择，能够提供灵活而高效的备份与恢复解决方案，确保数据的安全与可用性。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Incremental Backup" term="Incremental Backup"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL v4 逻辑复制槽同步功能解析]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-logical-replication-slot</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-logical-replication-slot"/>
        <updated>2025-03-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[IvorySQL v4 基于 PostgreSQL 17，引入了逻辑复制槽同步至热备份数据库的功能。这一改进有效解决了旧版本中主数据库与备份数据库切换后逻辑复制中断的问题。对于那些追求数据高可用性和业务连续性的数据库来说，这无疑是一个重大的利好消息。它不仅提升了系统的整体稳定性，还确保了在故障发生时，数据复制过程能够无缝继续，从而最大程度地降低了业务中断的可能性。]]></summary>
        <content type="html"><![CDATA[<p>IvorySQL v4 基于 PostgreSQL 17，引入了逻辑复制槽同步至热备份数据库的功能。这一改进有效解决了旧版本中主数据库与备份数据库切换后逻辑复制中断的问题。对于那些追求数据高可用性和业务连续性的数据库来说，这无疑是一个重大的利好消息。它不仅提升了系统的整体稳定性，还确保了在故障发生时，数据复制过程能够无缝继续，从而最大程度地降低了业务中断的可能性。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-1-b477c3d95d833e1ecff18533f5055692.png" width="1186" height="960" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="复制槽同步机制">复制槽同步机制<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E5%A4%8D%E5%88%B6%E6%A7%BD%E5%90%8C%E6%AD%A5%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="前提条件">前提条件<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class=""><strong>物理复制槽</strong>：主数据库与备份数据库之间必须存在物理复制槽，作为逻辑复制槽同步的基础，确保数据在主备之间有效传输。。</li>
<li class=""><strong>配置参数</strong>：<!-- -->
<ul>
<li class="">在备份数据库上配置 <code>primary_slot_name</code> 参数，并在使用 <code>pg_basebackup</code> 工具时指定复制槽。这一配置步骤确保了备份数据库能够正确接收主数据库数据。</li>
<li class="">启用备份数据库的 <code>hot_standby_feedback</code> 功能，确保其能接收并反馈 WAL 日志。这一功能的启用保证了备份数据库在接收数据时的活跃性和反馈机制的完整性。</li>
<li class="">在 <code>primary_conninfo</code> 参数中指定有效的数据库名称（<code>dbname</code>）。这一配置确保了复制过程中的目标数据库是明确且正确的。</li>
</ul>
</li>
<li class=""><strong>推荐配置</strong>：在主数据库上配置 <code>standby_slot_names</code> 参数以保持复制槽同步的一致性。这一配置有助于维护主备数据库间复制槽的一致状态，从而提高复制过程的可靠性。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="实现方式">实现方式<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>创建逻辑复制槽</strong>：
调用 <code>pg_create_logical_replication_slot</code> 函数时设置 <code>failover=true</code>，指定复制槽同步至备份数据库。这一设置至关重要，因为它决定了复制槽在主备切换时的行为。</p>
</li>
<li class="">
<p><strong>订阅配置</strong>：
使用 <code>CREATE SUBSCRIPTION</code> 语句时指定 <code>failover=true</code>，确保复制槽同步至备份数据库。这为数据库管理员提供了灵活的配置选项，使他们能够根据实际业务需求和环境特点定制复制策略。</p>
</li>
<li class="">
<p><strong>手动同步</strong>：
在备份数据库上执行 <code>pg_sync_replication_slots</code> 函数，手动同步复制槽。这种方法提供了一种即时同步的手段，特别适用于需要立即反映主数据库变更的场景。</p>
</li>
<li class="">
<p><strong>自动同步：</strong>
设置备份数据库的 <code>sync_replication_slots = on</code>，实现定期自动同步，无需重启数据库。这一自动化功能简化了数据库的维护工作，使管理员能够将更多精力投入到其他关键任务中。</p>
</li>
</ol>
<p>下图是配置及创建同步逻辑复制槽的流程图，详细的顺序讲解了如何配置同步逻辑复制槽基础参数，以及如何创建一个同步逻辑复制槽。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-2-e00b5bc5efe4913922963cdba55c9b26.png" width="1269" height="1126" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="函数与参数">函数与参数<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E5%87%BD%E6%95%B0%E4%B8%8E%E5%8F%82%E6%95%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ol>
<li class=""><code>pg_create_logical_replication_slot</code></li>
</ol>
<ul>
<li class="">新增了 failover 参数，其默认值为 false。若设置为 true，则表示该复制槽需同步至备份数据库。</li>
<li class="">示例语法：<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_create_logical_replication_slot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'test_slot'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'test_decoding'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">这一函数的引入，为数据库管理员提供了更精细的控制手段，使得逻辑复制槽的管理更加灵活和高效。</li>
</ul>
<ol start="2">
<li class=""><code>pg_sync_replication_slots</code></li>
</ol>
<ul>
<li class="">该函数用于手动同步复制槽至备份数据库。</li>
<li class="">示例语法：<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_sync_replication_slots</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">通过这一函数，可以即时地将主数据库的变更同步到备份数据库，确保数据的一致性和完整性。</li>
</ul>
<ol start="3">
<li class=""><code>sync_replication_slots</code></li>
</ol>
<ul>
<li class="">在备份数据库上设置该参数为 on，可实现复制槽变更的定期自动同步，无需重启数据库。</li>
<li class="">这一自动化设置极大地减轻了数据库管理员的负担，使得复制槽的维护工作更加轻松和高效。</li>
</ul>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-3-e368dd57bce7eec33a1d91b5aba72fbf.png" width="402" height="735" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-4-438cb045e492559d95e6371d26f3efe3.png" width="387" height="391" class="img_ev3q"></p>
<p>如上图所示，为主库和备库的复制槽的状态，主库创建了逻辑复制槽 <code>test_slots2</code>，并定义属性 failover 为 true，开启了这个槽的故障转移功能，通过手动或自动的方式，可以将逻辑复制槽 <code>test_slots2</code> 的状态及信息同步至备库，当发生主备切换或者故障转移时，备库被提升为新主时，逻辑复制槽 <code>test_slots2</code> 的信息将会保留，从而保证订阅端间断、不丢失数据。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="操作步骤与验证">操作步骤与验证<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4%E4%B8%8E%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="手动同步复制槽">手动同步复制槽<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E6%89%8B%E5%8A%A8%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6%E6%A7%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>搭建主数据库与备份数据库环境，确保主数据库和备份数据库的配置正确，包括物理复制槽和流复制用户。这一过程需要仔细规划和执行，以确保复制环境的稳定性和可靠性。</p>
<ol>
<li class="">创建复制槽：</li>
</ol>
<ul>
<li class="">执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_create_logical_replication_slot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'test_slot2'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'test_decoding'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">这一操作是逻辑复制槽同步的起点，它为后续的数据复制奠定了基础。</li>
</ul>
<ol start="2">
<li class="">在备份数据库上手动同步复制槽：</li>
</ol>
<ul>
<li class="">执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_sync_replication_slots</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">这一操作确保了复制槽的变更能够及时反映到备份数据库上，从而保证了数据的同步性和一致性。</li>
</ul>
<ol start="3">
<li class="">验证复制槽同步：</li>
</ol>
<ul>
<li class="">在备份数据库上执行查询，以确保复制槽已同步至备份数据库。</li>
<li class="">执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> \</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> pg_replication_slots</span><br></span></code></pre></div></div>
</li>
<li class="">这一验证步骤是确认复制槽同步成功的关键环节，它确保了复制过程的正确性和完整性。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="自动同步复制槽">自动同步复制槽<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E8%87%AA%E5%8A%A8%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6%E6%A7%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">在备份数据库上设置 <code>sync_replication_slots = on</code>：</li>
</ol>
<ul>
<li class="">执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">ALTER</span><span class="token plain"> SYSTEM </span><span class="token keyword" style="color:#00009f">SET</span><span class="token plain"> sync_replication_slots </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">on</span><br></span></code></pre></div></div>
</li>
<li class="">然后执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> pg_reload_conf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">这一自动化设置使得复制槽的同步工作更加简便和高效，管理员无需手动介入即可完成同步任务。</li>
</ul>
<ol start="2">
<li class="">
<p>验证自动同步：</p>
<p>在主数据库插入数据，观察备份数据库复制槽的变化，以确保主数据库复制槽的变更能够自动同步到备份数据库。这一验证步骤是确认自动同步功能正常工作的关键环节，它确保了复制过程的自动化和可靠性。</p>
</li>
</ol>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-5-6970523f5ffe31f36e0dbe1002dbc6a4.png" width="1029" height="298" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="模拟主数据库与备份数据库的切换">模拟主数据库与备份数据库的切换<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E6%A8%A1%E6%8B%9F%E4%B8%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8E%E5%A4%87%E4%BB%BD%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%88%87%E6%8D%A2" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<ol>
<li class="">在备份数据库上执行主数据库提升操作：</li>
</ol>
<ul>
<li class="">模拟主数据库故障，将主数据库关机。</li>
<li class="">在备份数据库上执行<!-- -->
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">D </span><span class="token keyword" style="color:#00009f">data</span><span class="token plain"> promote</span><br></span></code></pre></div></div>
</li>
<li class="">这一操作模拟了主数据库发生故障时的应急切换，是测试复制槽同步功能在实际故障场景中表现的重要步骤。</li>
</ul>
<ol start="2">
<li class="">
<p>在新的主数据库上继续进行逻辑复制：</p>
<p>在新的主数据库绑定 VIP，以确保逻辑复制能够继续进行。这一操作确保了在主数据库切换后，逻辑复制能够无缝地继续进行，从而保证了业务的连续性和数据的一致性。</p>
</li>
</ol>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-6-93a10935e1cfcbe01bd4281cefb0191d.png" width="1064" height="335" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-7-ff9ef06a8cf25189bfd6b3344337dc0a.png" width="1074" height="190" class="img_ev3q"></p>
<p>上图为切换后的新主，保留了原有的逻辑复制槽 <code>my_subscription</code> 和发布信息 <code>my_publication</code>。并且配置其他必要参数后，恢复新备库的逻辑复制槽同步能力。</p>
<p>订阅端根据 VIP 路由至新主数据库，继续使用同步的逻辑复制槽，保证逻辑复制的正常数据复制。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20250305-8-5a8ce2312c35d3a112e51651baf81824.png" width="1070" height="153" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://ivorysql.org/zh-cn/blog/ivorysql-logical-replication-slot#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>逻辑复制槽同步功能提升了 IvorySQL 在高可用性环境下的可靠性，解决了主数据库与备份数据库切换后逻辑复制槽丢失的问题。这一功能的引入，使得数据库面对主备切换时，保证逻辑复制槽的信息不丢失，确保了数据复制过程的连续性和一致性。</p>
<p>同步过程需满足以下条件：</p>
<ul>
<li class="">设置 <code>failover=true</code> 的复制槽；</li>
<li class="">主数据库与备份数据库间配置物理复制槽；</li>
<li class="">备份数据库启用 <code>hot_standby_feedback</code>；</li>
<li class="">备份数据库的 <code>primary_conninfo</code> 参数配置正确的数据库名称；</li>
<li class="">推荐配置 <code>standby_slot_names</code> 参数以确保一致性；</li>
<li class="">通过 <code>pg_sync_replication_slots</code> 或 <code>sync_replication_slots</code> 参数，备份数据库可以手动或自动同步复制槽，确保逻辑复制能够无缝切换。</li>
</ul>
<p>这一系列的措施和功能，共同构成了 IvorySQL 中逻辑复制槽同步功能的强大和灵活，为数据库管理员提供了强大的工具，以应对各种复杂和挑战性的数据复制场景。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Logical Replication Slot" term="Logical Replication Slot"/>
        <category label="逻辑复制槽" term="逻辑复制槽"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 4.0 之 Invisible Column 功能解析]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-invisible-column</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-invisible-column"/>
        <updated>2025-01-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[前言]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="前言">前言<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#%E5%89%8D%E8%A8%80" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>随着数据库应用场景的多样化，用户对数据管理的灵活性和隐私性提出了更高要求。IvorySQL 作为一款基于 PostgreSQL 并兼容 Oracle 的开源数据库，始终致力于在功能上保持领先和创新。在最新发布的 4.0 版本中，<strong>IvorySQL 新增了 Oracle 兼容特性 <a href="https://github.com/IvorySQL/IvorySQL/pull/679" target="_blank" rel="noopener noreferrer" class="">Invisible Column</a>（不可见列），这一功能由社区贡献者 <a href="https://github.com/imranzaheer612" target="_blank" rel="noopener noreferrer" class="">Imran Zaheer</a> 提供，体现了开源社区协作的力量</strong>。</p>
<p>Invisible Column 的引入，为开发者提供了在不影响现有应用的情况下动态调整数据库结构的新选择，进一步提升了 IvorySQL 在数据灵活性管理上的能力，为用户在数据库升级、兼容性优化等方面提供了更大的便利性。</p>
<p>本文将详细介绍这一特性的功能、使用场景以及使用方式。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="什么是-invisible-column">什么是 Invisible Column？<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#%E4%BB%80%E4%B9%88%E6%98%AF-invisible-column" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在现代数据库开发中，列的可见性管理在一定程度上影响了应用程序的灵活性与迁移效率。Oracle 12c 提供了一项强大的功能：Invisible Column（不可见列）。这是一种隐藏数据列的特性，用于增强数据安全性和实现业务逻辑。这一功能为开发者提供了灵活性和控制能力，特别是在应用程序迁移或版本升级的场景中。</p>
<p>在 Oracle 中，Invisible Column 是指那些对大多数 SQL 查询和工具不可见的列。通过将列设置为不可见列：</p>
<ul>
<li class="">它不会出现在常规的 <code>SELECT * FROM</code> 查询结果中。</li>
<li class="">它不会在 <code>SQL*Plus</code> 或 <code>OCI</code> 的描述操作中显示。</li>
<li class="">它不会包含在基于 <code>%ROWTYPE</code> 属性的记录定义中。</li>
</ul>
<p>然而，不可见列仍然存在于表中，可以通过显式指定列名来访问或引用。另外，不可见列在使用时也有限制，要注意在外部表（External Tables）、聚簇表（Cluster Tables）、临时表（Temporary Tables）中无法使用不可见列。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="invisible-column-的应用场景">Invisible Column 的应用场景<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#invisible-column-%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-应用程序迁移">1. 应用程序迁移<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#1-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E8%BF%81%E7%A7%BB" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>不可见列在应用程序迁移过程中非常有用。当我们向现有表中添加新列时，不可见列可以避免影响旧应用程序的功能。旧的应用程序不会察觉新列的存在，而新的应用程序可以显式引用这些列。从而使应用程序的在线迁移变得更加简单顺畅。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-敏感数据保护">2. 敏感数据保护<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#2-%E6%95%8F%E6%84%9F%E6%95%B0%E6%8D%AE%E4%BF%9D%E6%8A%A4" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>某些敏感数据可以通过不可见列存储，避免被大多数默认查询工具访问，从而降低意外暴露的风险。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-数据模型优化">3. 数据模型优化<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#3-%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E4%BC%98%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在数据模型调整或调试过程中，可以临时将一些列设置为不可见列，确保它们不会影响常规查询，避免查询结果混淆。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="在-ivorysql-中使用-invisible-column">在 IvorySQL 中使用 Invisible Column<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#%E5%9C%A8-ivorysql-%E4%B8%AD%E4%BD%BF%E7%94%A8-invisible-column" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>Invisible Column 为 IvorySQL 4.0 版本中新增加的兼容特性，使用前请先确保您的版本为 4.0。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-创建不可见列">1. 创建不可见列<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#1-%E5%88%9B%E5%BB%BA%E4%B8%8D%E5%8F%AF%E8%A7%81%E5%88%97" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>可以在创建表时直接将列定义为不可见列：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE TABLE employees (</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">emp_id NUMBER,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">emp_name VARCHAR2(50),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">emp_salary NUMBER INVISIBLE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span></code></pre></div></div>
<p>在此示例中，<code>emp_salary</code> 是不可见列，对默认查询不可见：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">select*from employees ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">emp_id | emp_name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--------+----------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(0 rows)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-向不可见列插入数据">2. 向不可见列插入数据<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#2-%E5%90%91%E4%B8%8D%E5%8F%AF%E8%A7%81%E5%88%97%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在向表中插入数据时，可以通过显式指定列名的方式向不可见列插入数据：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO employees(emp_id,emp_name,emp_salary) VALUES(1,'Jack',20000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT 0 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO employees(emp_id,emp_name,emp_salary) VALUES(2,'Lucy',30000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT 0 1;</span><br></span></code></pre></div></div>
<p>不带命名列的插入不能包含不可见列：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO employees VALUES(3,'Peter');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT 0 1</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-显示修改现有列为不可见列">3. 显示/修改现有列为不可见列<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#3-%E6%98%BE%E7%A4%BA%E4%BF%AE%E6%94%B9%E7%8E%B0%E6%9C%89%E5%88%97%E4%B8%BA%E4%B8%8D%E5%8F%AF%E8%A7%81%E5%88%97" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>通过 <code>VISIBLE</code> 关键字，可以将不可见列改回普通列：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ALTER TABLE employees MODIFY emp_salary VISIBLE;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ALTER TABLE</span><br></span></code></pre></div></div>
<p>如果需要将现有列设置为不可见列，可以使用 <code>INVISIBLE</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ALTER TABLE employees MODIFY emp_salary INVISIBLE;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ALTER TABLE</span><br></span></code></pre></div></div>
<p>注意，不能将所有的列设置为不可见列。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-psql-d-元命令">4. psql \d 元命令<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#4-psql-d-%E5%85%83%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在 psql 中使用 <code>\d</code> 元命令时不会显示该表的不可见列信息：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">\d employees</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                  Table "public.employees"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Column   |     Type     | Collation | Nullable | Default </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">------------+--------------+-----------+----------+---------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_id     | number       |           |          | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_name   | varchar2(50) |           |          | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_salary | number       |           |          | </span><br></span></code></pre></div></div>
<p>可以使用含有更多表信息的 <code>\d+</code> 元命令查看该表的不可见列信息：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">\d+ employees</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                                   Table "public.employees"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Column   |     Type     | Collation | Nullable | Default | Invisible | Storage  | Compression | Stats target | Description </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">------------+--------------+-----------+----------+---------+-----------+----------+-------------+--------------+-------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_id     | number       |           |          |         |           | main     |             |              | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_name   | varchar2(50) |           |          |         |           | extended |             |              | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_salary | number       |           |          |         | invisible | main     |             |              | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Access method: heap</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-访问-invisible-column">5. 访问 Invisible Column<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#5-%E8%AE%BF%E9%97%AE-invisible-column" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在使用 <code>SELECT*</code> 查询表数据时，不会显示不可见列的数据：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">SELECT * FROM employees ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_id | emp_name </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--------+----------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 1      | Jack</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 2      | Lucy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 3      | Peter</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(3 rows)</span><br></span></code></pre></div></div>
<p>虽然不可见列对默认查询不可见，但开发者仍然可以通过显式指定列名来访问它：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">SELECT emp_name,emp_salary FROM employees ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> emp_name | emp_salary </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">----------+------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Jack     | 20000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Lucy     | 30000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Peter    | </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(3 rows)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="结语">结语<a href="https://ivorysql.org/zh-cn/blog/ivorysql-invisible-column#%E7%BB%93%E8%AF%AD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>不可见列功能是一项设计精妙的特性，为数据库开发和管理提供了更高的灵活性和安全性。通过合理利用不可见列，开发者可以轻松应对复杂的应用迁移场景，同时保持系统的稳定性和可扩展性。</p>
<p>如果您有正在使用 IvorySQL 数据库的项目，不妨尝试将此功能集成到您的解决方案中，提升整体效率和可靠性。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Invisible Column" term="Invisible Column"/>
        <category label="不可见列" term="不可见列"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 4.0 之兼容 Oracle 包功能设计思路解读]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-oracle-package-compatibility</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-oracle-package-compatibility"/>
        <updated>2025-01-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[日前，IvorySQL 4.0 发布，该版本新增了兼容 Oracle 包功能的新特性。]]></summary>
        <content type="html"><![CDATA[<p>日前，IvorySQL 4.0 发布，该版本新增了兼容 Oracle 包功能的新特性。</p>
<p>为了大家能够更好地理解和使用 IvorySQL 4.0，本文将简要介绍实现此功能时的设计思路。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="oracle-的包是什么">Oracle 的包是什么？<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#oracle-%E7%9A%84%E5%8C%85%E6%98%AF%E4%BB%80%E4%B9%88" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>包是包含了逻辑上相关的 PL/SQL 类型、变量、常量、子过程、游标和异常的一个模式对象。包被编译并存储在数据库中，多个应用可以共享包的内容。</p>
<p>包总是有一个包规范，包规范中声明了公有对象，这些公有对象可以在包外被引用。</p>
<p>如果公有对象中包含了游标或子过程，则包必须有一个包体。包体必须定义公有游标和公有子过程的代码。包体也可以声明并定义私有对象，私有对象不能在包外被引用，但可用于包内使用。最后，包体可以有一个初始化部分，这部分用于初始化变量，做一些一次性的设置步骤和异常处理。修改包体的时候，可以不修改包规范或引用包的公有对象的数据库对象，因此可以认为包体是一个黑盒。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ivorysql-中包的实现">IvorySQL 中包的实现<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#ivorysql-%E4%B8%AD%E5%8C%85%E7%9A%84%E5%AE%9E%E7%8E%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>从内容来看，包体与嵌套子过程类似，包规范只是定义包体对外的接口，因此，从实现角度来看，包的实现过程可以和嵌套子过程类似。</p>
<p>我们主要处理的工作有如下几个方面：包的创建、更新、实例化、删除以及外部过程对包规范中包对象的引用。</p>
<ul>
<li class=""><strong>包的创建：</strong> 修改 psql 语法，使 psql 能将整个包的创建语句整体发到服务器，在服务器中增加包的创建语法，语法结构基本上和普通函数类似，因此与函数类似，无需在 SQL 端展开。包创建经过语法解析后走 DDL 流程，调用包的创建函数，将包的内容存储到系统表里面去。</li>
<li class=""><strong>包的更新：</strong> 在 SQL 端支持更新语法，经语法解析后，调用包的更新函数，更新系统表内容，调用 <code>plisql_package_Handler</code> 走一遍 <code>pl_gram.y</code>，并失效包规范元组或包体元组，这样避免在运行时编译包和包体。</li>
<li class=""><strong>包的删除：</strong> 需要在 SQL 端支持其删除语法，经语法解析后，调用包的删除函数，删除系统表该包的内容。</li>
<li class=""><strong>包的实例化：</strong> 在第一次引用包的时候，如果包的内容没有在内存中(具体来说是一个 hash 表，类似于 portal 的 hash 表存储)，则调用包的实例化函数，将包重新实例化，实例化其实是调用 PL/iSQL 端的 compile 函数，将包规范与包体重新编译，并将编译的结果放在当前进程的内存里，包的实例化应该是将包与包体的整体内容加载到内存中。</li>
<li class=""><strong>包对象引用：</strong> 在 parse 阶段，提供查找包规范中的变量，类型、子过程的接口，优先在本模式下查找包中类型，然后查找系统表中的类型，在查找子过程时，优先在嵌套函数、包中、系统表中查找。</li>
<li class=""><strong>包的失效与包的状态：</strong> 包中如果全是常量与类型，则包无状态，否则包是有状态的。包的状态在访问包的变量与函数时设置，在重建包时，会让包的本地实例失效，并且本地重新编译实例化，其他进程的包实例，如果包是有状态的，访问包中变量或类型，则首次访问报包的状态丢失错误，其后正常访问。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ivorysql-中包的设计">IvorySQL 中包的设计<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#ivorysql-%E4%B8%AD%E5%8C%85%E7%9A%84%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="新增的系统表与缓存">新增的系统表与缓存<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E6%96%B0%E5%A2%9E%E7%9A%84%E7%B3%BB%E7%BB%9F%E8%A1%A8%E4%B8%8E%E7%BC%93%E5%AD%98" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>为了存储包体与包规范内容，新增了 2 个系统表：</p>
<table><thead><tr><th>系统表名称</th><th>作用</th></tr></thead><tbody><tr><td><code>pg_package.h</code></td><td>存储包规范内容</td></tr><tr><td><code>pg_package_body.h</code></td><td>存储包体内容</td></tr></tbody></table>
<p>对应的系统缓存则有 4 个：</p>
<table><thead><tr><th>系统缓存名称</th><th>作用</th></tr></thead><tbody><tr><td><code>PKGBODYOID</code></td><td>根据包体的 OID 查找包体的元组</td></tr><tr><td><code>PKGBODYPKGID</code></td><td>根据包规范的 OID 查找包体的元组</td></tr><tr><td><code>PKGNAMEARGSNSP</code></td><td>根据包名和模式的 OID 查找包的元组</td></tr><tr><td><code>PKGOID</code></td><td>根据包规范的 OID 查找包的元组</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="包的实例化">包的实例化<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E5%8C%85%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>包的实例化，类似于函数编译，是将用字符串定义的数据，转换成结构化数据。包的内容是由包规范和包体两部分构成，因此，包的编译需要进行一些特殊处理。增加相应的新函数分别编译包规范和包体，并将结果缓存到哈希表中。</p>
<p>另外，为了处理在删除包与包体的时候，本地缓存会失效，在创建包缓存的时候，注册一个包的失效函数，用来处理包的失效时，需要清除包的缓存状态。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/* register invalid cache */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CacheRegisterSyscacheCallback(PKGBODYOID, InvalidatePackageCacheCallback, (Datum) 0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CacheRegisterSyscacheCallback(PKGOID, InvalidatePackageCacheCallback, (Datum) 0);</span><br></span></code></pre></div></div>
<p><code>InvalidatePackageCacheCallback</code> 将根据 hash 值，遍历 hash 表中的每一项，更新相应包的缓存状态。</p>
<p>包的缓存状态用一个 char 来表示，目前只用到三位 bit，<code>0x01</code> 表示包规范被更新了，<code>0x02</code> 表示包是否有包体，<code>0x04</code> 表示包体被更新了。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="包中对象的引用">包中对象的引用<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E5%8C%85%E4%B8%AD%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BC%95%E7%94%A8" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>提供查找包中函数、类型、变量的接口，供 parse 阶段使用，以下是部分函数列表。</p>
<table><thead><tr><th>函数名称</th><th>参数</th><th>返回值</th><th>说明</th></tr></thead><tbody><tr><td><code>LookupPkgTypeByTypename</code></td><td><code>Const List* names</code>，<code>Bool missing_ok</code></td><td><code>PkgType*</code></td><td>根据语法阶段构造类型名称列表，查看是否是包中的类型。</td></tr><tr><td><code>LookupPkgVarByvarnames</code></td><td><code>Const List _names</code>, <code>Bool missing_ok</code></td><td><code>PkgVar*</code></td><td>根据变量名称，查看是否是包中的变量</td></tr><tr><td><code>LookupPkgEntryByTypename</code></td><td><code>const List *names</code>, <code>bool missing_ok</code></td><td><code>PkgEntry </code></td><td>根据名称，返回包中属性（类型或变量）</td></tr><tr><td><code>LookupPkgFunc</code></td><td><code>ParseState *pstate</code>, <code>List *fargs, FuncCall *fn</code></td><td><code>FuncExpr</code></td><td>根据函数名称，查看是否是包中的函数</td></tr></tbody></table>
<p>在 PL/iSQL 非包内函数使用包的类型时，只需将类型的地址引用过来，而使用变量时，则需做一份本地映射，当涉及到该类的变量赋值时，需要进行特殊处理。一般来说，主要是切换到包的内存上下文，然后调用包的赋值函数。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="函数形参或返回值引用包的类型">函数形参或返回值引用包的类型<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E5%87%BD%E6%95%B0%E5%BD%A2%E5%8F%82%E6%88%96%E8%BF%94%E5%9B%9E%E5%80%BC%E5%BC%95%E7%94%A8%E5%8C%85%E7%9A%84%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>该部分需要修改 <code>pg_proc</code> 系统表的结构，需要增加字段来记录参数类型和返回值类型的名称，故在系统表中增加参数类型名称和返回值类型名称两列即可解决。</p>
<p>类似于 <code>proargnames</code>，增加 <code>protypenames</code> 用于记录参数类型的类型名称，增加 <code>rettypename</code> 记录返回值类型的名称。只有当相关项引用包的类型时赋值，不然为空。</p>
<p>因为 <code>protypnames</code> 是一个 text 数组，因此当有一个函数参数是包中类型时，该数组就不为空，且参数类型为包的项是由 <code>TypeName</code> 结构字符序列化得到，其他非包的参数类型为空字符串。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="standard-包">standard 包<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#standard-%E5%8C%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>支持 sys 模式下的 standard 包，可以不用带包名进行访问包中规范的对象，用户可以自行创建 standard 包。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="discard-package-语法">DISCARD PACKAGE 语法<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#discard-package-%E8%AF%AD%E6%B3%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>该功能是为兼容 PostgreSQL 的 <code>DISCARD</code> 功能做的，目前 PostgreSQL 支持 <code>DISCARD SEQUENCE</code>、<code>DISCARD TEMP</code>、<code>DISCARD PLAN</code> 等用来删除当前 session 的序列、临时表以及计划等缓存，并且 DISCARD ALL 支持删除本 session 的 PORTAL、临时表、计划、序列等临时存储。</p>
<p>IvorySQL 支持 DISCARD PACKAGE 语法，并且在 DISCARD ALL 中调用函数删除本 session 的包缓存。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="逻辑备份还原支持包">逻辑备份还原支持包<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E9%80%BB%E8%BE%91%E5%A4%87%E4%BB%BD%E8%BF%98%E5%8E%9F%E6%94%AF%E6%8C%81%E5%8C%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在 <code>pg_dump</code> 工具中，包功能也得到了支持，用户可以使用 <code>pg_dump</code> 对包功能在内的数据进行备份恢复。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://ivorysql.org/zh-cn/blog/ivorysql-oracle-package-compatibility#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>以上就是实现兼容 Oracle 包功能时的设计思路。</p>
<p>通过包的形式将相关的功能模块化，使得数据库的过程、函数、变量和其他编程元素组织在一起形成自包含单元，便于管理和维护。由于实现细节隐藏在包体中，提高了代码的安全性和可维护性。包体中的代码在第一次调用时被加载到内存中，后续调用可以直接使用，减少了解析和加载时间。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Oracle Package" term="Oracle Package"/>
        <category label="Package" term="Package"/>
        <category label="包功能" term="包功能"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 升级指南：从 3.x 到 4.0 的平滑过渡]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0"/>
        <updated>2025-01-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[日前，IvorySQL 4.0 重磅发布，全面支持 PostgreSQL 17，并且增强了对 Oracle 的兼容性。]]></summary>
        <content type="html"><![CDATA[<p>日前，IvorySQL 4.0 重磅发布，全面支持 PostgreSQL 17，并且增强了对 Oracle 的兼容性。</p>
<p>本篇文章将详细描述，如何从 IvorySQL 3.x 升级到 IvorySQL 4.0。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pg_upgrade-工具介绍"><code>pg_upgrade</code> 工具介绍<a href="https://ivorysql.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0#pg_upgrade-%E5%B7%A5%E5%85%B7%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><code>pg_upgrade</code> 工具是 PostgreSQL 内置的跨版本升级工具，能够对数据库就地升级，不需要执行导出和导入操作。IvorySQL 源自于 PG，因此也能够使用 <code>pg_upgrade</code> 工具进行大版本升级。</p>
<p><code>pg_upgrade</code> 提供了升级前的兼容性检查（<code>-c</code> 或者 <code>--check</code> 选项）功能，可以发现插件、数据类型不兼容等问题。如果指定了 <code>--link</code> 选项，新版本服务可以直接使用原有的数据库文件而不需要执行复制，通常可以在几分钟内完成升级操作。</p>
<p>常用的参数包括：</p>
<ul>
<li class=""><code>-b bindir，--old-bindir=bindir</code>：旧的 IvorySQL&nbsp; 可执行文件目录</li>
<li class=""><code>-B bindir，--new-bindir=bindir</code>：新的 IvorySQL 可执行文件目录</li>
<li class=""><code>-d configdir，--old-datadir=configdir</code>：旧版本的数据目录</li>
<li class=""><code>-D configdir，--new-datadir=configdir</code>：新版本的数据目录</li>
<li class=""><code>-c，--check</code>：只检查升级兼容性，不更改任何数据</li>
<li class=""><code>-k，--link</code>：硬链接方式升级</li>
</ul>
<p>下面介绍一下在 CentOS 8 平台上如何使用 <code>pg_upgrade</code> 将 IvorySQL 升级到最新的 4.0 版本。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="升级准备">升级准备<a href="https://ivorysql.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0#%E5%8D%87%E7%BA%A7%E5%87%86%E5%A4%87" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>首先停止旧版本的 IvorySQL 3.4 数据库：</p>
<p><img decoding="async" loading="lazy" alt="img" src="data:image/png;base64,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" width="834" height="64" class="img_ev3q"></p>
<p>然后安装新版本的 IvorySQL 4.0 数据库：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-2-4563181ec2bad457c0a3d4128446a4ed.png" width="1160" height="466" class="img_ev3q"></p>
<p>初始化新版 IvorySQL 4.0 数据目录：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-3-4ff2c0afcb6fb47d079ab171e261f9e5.png" width="687" height="183" class="img_ev3q"></p>
<p>检查版本兼容性：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-4-00c330bd4aead0fffb85712501b2a4b7.png" width="1171" height="322" class="img_ev3q"></p>
<p>最后出现 <code>Clusters are compatible</code> 表明两个版本之间的数据不存在兼容性问题，可以进行升级。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="正式升级">正式升级<a href="https://ivorysql.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0#%E6%AD%A3%E5%BC%8F%E5%8D%87%E7%BA%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-5-999ed695e72bae1ac12ce5ac9535d8dc.png" width="1159" height="410" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-6-5682919a2e7af771ba72f93045ce233a.png" width="1140" height="665" class="img_ev3q"></p>
<p>看到 <code>Upgrade&nbsp;Complete</code> 说明升级已经顺利完成。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="更新统计信息">更新统计信息<a href="https://ivorysql.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0#%E6%9B%B4%E6%96%B0%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><code>pg_upgrade</code> 会创建新的系统表，并重用旧的数据进行升级，统计信息并不会随升级过程迁移，所以在启用新版本之前，应该首先重新收集统计信息，避免没有统计信息导致错误的查询计划。</p>
<p>首先启动新版本数据库：</p>
<p><img decoding="async" loading="lazy" alt="img" src="data:image/png;base64,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" width="849" height="61" class="img_ev3q"></p>
<p>手动运行 <code>vacuum</code> 命令：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/up-to-4.0-8-be2c7b52deda5bab3fd79616a2f8986a.png" width="880" height="206" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="升级后的清理">升级后的清理<a href="https://ivorysql.org/zh-cn/blog/ivorysql-upgrade-3.x-to-4.0#%E5%8D%87%E7%BA%A7%E5%90%8E%E7%9A%84%E6%B8%85%E7%90%86" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>确认没有问题后删除旧库：</p>
<p><img decoding="async" loading="lazy" alt="img" src="data:image/png;base64,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" width="547" height="103" class="img_ev3q"></p>
<p>至此，我们就完成了整个升级过程。</p>
<p>如果您在后续的升级过程中，遇到问题，可以在 GitHub 上提交 <a href="https://github.com/IvorySQL/IvorySQL/issues" target="_blank" rel="noopener noreferrer" class="">issue</a>，我们将及时为您解答。同时，如果您对 IvorySQL 后续的功能迭代有任何想法或者期待，也可以提交 issue 反馈给我们。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 数据库中的外部存储管理器]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-external-storage-manager</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-external-storage-manager"/>
        <updated>2024-12-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[一般来说，数据库的存储系统分为内存和外存两个部分，而除了内存数据库之外，数据最终都是持久化存储的，持久化就要将数据从内存 buffer 落盘到外存，因此今天我们来聊聊 IvorySQL 中的外部存储管理器。]]></summary>
        <content type="html"><![CDATA[<p>一般来说，数据库的存储系统分为内存和外存两个部分，而除了内存数据库之外，数据最终都是持久化存储的，持久化就要将数据从内存 buffer 落盘到外存，因此今天我们来聊聊 IvorySQL 中的外部存储管理器。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="存储文件的分类">存储文件的分类<a href="https://ivorysql.org/zh-cn/blog/ivorysql-external-storage-manager#%E5%AD%98%E5%82%A8%E6%96%87%E4%BB%B6%E7%9A%84%E5%88%86%E7%B1%BB" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL 数据库使用的存储管理器基本上与 PostgreSQL 相同，其文件目录及文件组织结构如下图：</p>
<p><img decoding="async" loading="lazy" alt="image" src="https://ivorysql.org/zh-cn/assets/images/20241205-1-81c420b46fe7becf37e20f7b7ad62dfc.png" width="800" height="326" class="img_ev3q"></p>
<p>从存储的角度看，文件管理分为 3 个主要部分：</p>
<ul>
<li class="">配置相关的文件，比如 <code>pg_control</code>，<code>postgresql.conf</code>，<code>pg_hba.conf</code>，<code>PG_VERSION</code> 等；</li>
<li class="">WAL 日志文件，<code>000000010000000000000001</code>， <code>000000010000000000000002</code> 等；</li>
<li class="">表，索引的数据记录文件，相应的剩余空间和可见性映射文件等。</li>
</ul>
<p>配置相关的文件在 PostgreSQL 中使用标准文件读写函数处理，比如：记录数据库状态和操作的 <code>pg_control</code> 文件。其中后台模块通过 <code>ReadControlFile()</code>，<code>WriteControlFile()</code>，<code>UpdateControlFile()</code>&nbsp; 进行读写操作。前台工具通过 <code>get_controlfile()</code>，<code>update_controlfile()</code>&nbsp; 进行读写操作。无论前台还是后台，这些读写操作最终还是通过标准文件操作函数 <code>open()</code>，<code>read()</code>，<code>write()</code>&nbsp; 进行。这些对配置文件的直接操作不在 SMGR 管控范畴。</p>
<p>WAL 日志文件最终也是通过标准文件函数 <code>read()</code>，<code>write()</code> 等等完成读写（和配置文件类似）。但不同的是，文件名需要根据 LSN 动态计算获取。</p>
<p>表，索引数据记录存储在 base 目录下的相应数据库的子目录下。集群级别的 catalog（系统表）数据记录变化则反映在 global 目录下。系统表的管理与用户表类似，同样采用 OID 的命名方式。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sql-语句访问存储介质过程-">SQL 语句访问存储介质过程 &nbsp;<a href="https://ivorysql.org/zh-cn/blog/ivorysql-external-storage-manager#sql-%E8%AF%AD%E5%8F%A5%E8%AE%BF%E9%97%AE%E5%AD%98%E5%82%A8%E4%BB%8B%E8%B4%A8%E8%BF%87%E7%A8%8B-" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>一条 SQL 语句通常按照如下路径访问一个磁盘上的数据记录：</p>
<ul>
<li class="">首先语句先经过 5 阶段的查询处理：parse，rewrite，analyze，plan，execute。</li>
<li class="">再进到 Table/Index Access Method 层。</li>
<li class="">Access Method 层通常会使用 Buffer Manager 服务，对数据条目进行操作，根据操作决定是否将数据块标记为“脏”。</li>
<li class="">Buffer Manager 层会使用 Storage Manager 服务，根据 buffer tag 调用 <code>smgr_read()</code> 或 <code>smgr_write()</code> 来读取或写数据到存储介质。</li>
</ul>
<p><img decoding="async" loading="lazy" alt="image" src="https://ivorysql.org/zh-cn/assets/images/20241205-2-45a8c4c03cd3924a611d28e5f9ef8e88.png" width="883" height="332" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="smgr-api-接口-">SMGR API 接口 &nbsp;<a href="https://ivorysql.org/zh-cn/blog/ivorysql-external-storage-manager#smgr-api-%E6%8E%A5%E5%8F%A3-" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>PostgreSQL 原本有许多 SMGR API 接口的实现，但目前只留下 Magnetic Disk（md.c）的实现（磁盘)。实际上，磁盘管理器可以支持任何类型的设备，只要操作系统为该设备提供了标准的文件系统操作接口。但是保留存储管理器（smgr.c）这个中间层，以防有人引入其他类型的存储管理器。删除中间层不会节省明显的开销，因为对存储介质的操作，比一层 c 语言函数调用昂贵的多的多。<code>f_smgr</code> 是一组函数指针结构，包含了 PostgreSQL 对存储所需要的函数。<code>smgr.c</code> 定义所有函数接口的 wrapper 函数，这些 wrapper 会最终调用实际注册的实现函数，也就是 <code>mdXXXX</code> 函数。</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> f_smgr smgrsw</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/* magnetic disk */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_init </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdinit</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_shutdown </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_open </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdopen</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_close </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdclose</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_create </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdcreate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_exists </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdexists</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_unlink </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdunlink</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_extend </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdextend</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_prefetch </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdprefetch</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_read </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdread</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_write </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdwrite</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_writeback </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdwriteback</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_nblocks </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdnblocks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_truncate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdtruncate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">smgr_immedsync </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mdimmedsync</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>SMgrRelation 是一个重要的结构体，几乎所有和 SMGR 相关的函数都需要这个结构。</p>
<p><img decoding="async" loading="lazy" alt="image" src="https://ivorysql.org/zh-cn/assets/images/20241205-3-de0b8bf23c570f764841c5aa2e33160a.png" width="1197" height="923" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="smgr-关键接口函数-">SMGR 关键接口函数 &nbsp;<a href="https://ivorysql.org/zh-cn/blog/ivorysql-external-storage-manager#smgr-%E5%85%B3%E9%94%AE%E6%8E%A5%E5%8F%A3%E5%87%BD%E6%95%B0-" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ul>
<li class="">
<p><code>Smgrread()</code> 根据 5 个参数：tablespace，database，relation，forknum 和 blocknum 定位一个 8K 数据块，并将其读入指定的内存中。</p>
<p><code>smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char * buffer)</code></p>
</li>
<li class="">
<p><code>Smgrwrite()</code> 根据 5 个参数定位一个 8K 数据块，然后用指定内存中的值将其覆盖。根据 skipFsync 决定是否在返回前保证数据落盘成功。</p>
<p><code>smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char * buffer, bool skipFsync)</code></p>
</li>
<li class="">
<p>smgrextend 负责在当前文件中扩展一个新的 8K 块并写入指定内存中的数据，其他与 smgrwrite 相同。</p>
<p><code>smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char * buffer, bool skipFsync)</code></p>
</li>
<li class="">
<p>smgrnblocks 返回指定表当前的 8K 数据块总数，这个值对语句处理的 planner 环节很重要。</p>
<p><code>smgrnblocks(SMgrRelation reln, ForkNumber forknum)</code></p>
</li>
<li class="">
<p>对象共同存在。</p>
<p><code>smgropen(RelFileNode rnode, BackendId backend)</code></p>
</li>
<li class="">
<p>smgrclose 负责从哈希表中删除指定的 SMgrRelation 对象。</p>
<p><code>smgrclose(SMgrRelation reln)</code></p>
</li>
<li class="">
<p>smgrtruncate 用于从文件（数据，剩余空间，可见性）中从后往前去删除指定数量的 8K 数据块，可以一次对上述 3 个 fork 文件分别去除多个数据块，最终缩小文件尺寸。</p>
<p><code>smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)</code></p>
</li>
<li class="">
<p>smgrprefetch 利用 POSIX_FADV_WILLNEED 提供的服务要求操作系统提前读取磁盘数据块到缓存中，这个动作可避免磁盘 I/O 瓶颈。</p>
<p><code>smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)</code></p>
</li>
</ul>
<p>smgrwrite 和 smgrextend 是写磁盘相关的重要函数，也是影响系统 I/O 性能的关键。它们在以下场景下被调用：</p>
<ul>
<li class="">smgrwrite：<!-- -->
<ul>
<li class="">当一个缓冲区（Buffer）被修改（即脏数据）时，调用 smgrwrite 将数据写到磁盘上的对应文件中；</li>
<li class="">当事务提交时，需要确保已经将所有的脏数据写回磁盘，这就需要调用 smgrwrite；</li>
<li class="">在 VACUUM 操作中，当对表的可见性信息进行更新时，相应的缓冲区可能会变为脏数据，需要通过 smgrwrite 将其写进磁盘；</li>
</ul>
</li>
<li class="">smgrextend：<!-- -->
<ul>
<li class="">当需要扩展一个文件（表或索引）时，调用 smgrextend 将文件扩展到所需的大小；</li>
<li class="">创建一个新表或索引时，需要确定其初始大小，也会调用 smgrextend；</li>
<li class="">执行 CLUSTER 操作时，需要将表重新组织，也可能会调用 smgrextend；</li>
<li class="">smgrwrite 和 smgrextend 用于确保数据的持久性，smgrwrite 用于将修改的数据写进磁盘，而 smgrextend 用于扩展文件大小。</li>
</ul>
</li>
</ul>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Storage Manager" term="Storage Manager"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 高可用：逻辑复制槽零丢失]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots"/>
        <updated>2024-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[前言]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="前言">前言<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E5%89%8D%E8%A8%80" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在数据库高可用架构中，逻辑复制是实现数据同步和扩展的重要机制之一。通过逻辑复制，数据库管理员可以选择性地复制特定表的数据，而不必像物理复制那样进行全量数据库实例的复制。然而，逻辑复制槽的局限性在于它仅存在于主节点上，导致主备切换后新主节点无法继续向下游发送数据变更，直到重新创建或手动恢复逻辑复制槽。这种情况可能引发数据丢失，或者需要管理员手动干预，影响业务的连续性。</p>
<p>PostgreSQL 作为优秀的开源关系型数据库，提供了多种高可用性工具，其中 <code>pg_failover_slot</code> 插件专门解决了逻辑复制槽在主备切换时无法同步的问题，而 IvorySQL 作为一款基于 PostgreSQL 研发的兼容 Oracle 的数据库，同样适配该插件。</p>
<p>本文将详细介绍如何安装和配置 <code>pg_failover_slot</code> 插件，并说明它如何帮助 IvorySQL 实现无缝的逻辑复制槽同步。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="逻辑复制槽的原理及局限性">逻辑复制槽的原理及局限性<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E5%8E%9F%E7%90%86%E5%8F%8A%E5%B1%80%E9%99%90%E6%80%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在 PostgreSQL 中，逻辑复制与物理复制不同，它允许对特定表的数据变动进行行级别的精细化控制，并可以跨数据库版本和架构同步数据。逻辑复制的关键是通过逻辑复制槽记录并维护主节点上的数据变更，这些变更可以被下游的订阅者捕获和应用。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="逻辑复制槽的工作原理">逻辑复制槽的工作原理<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>逻辑复制槽是 PostgreSQL 维护数据变更的缓冲机制，它存储了自上次传输以来的数据增量，直到下游订阅者成功接收这些数据。复制槽还记录了下游订阅者接收到的最后一个变更，以便在系统故障或网络问题时重新发送未完成的数据。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="逻辑复制槽的局限性">逻辑复制槽的局限性<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>逻辑复制槽仅在主节点上维护，因此在以下情况下会遇到问题：</p>
<ul>
<li class="">故障转移后的数据丢失：当主节点宕机并且备节点被提升为主节点时，新的主节点没有复制槽的记录。此时，订阅者无法从新的主节点获取数据变更，直到管理员在新主节点上手动创建新的复制槽。</li>
<li class="">需要逻辑复制槽的手动创建及重新初始化：手动创建复制槽不仅繁琐，而且会造成数据同步的中断，可能需要重新初始化逻辑复制表，带来额外的负载和复杂度。</li>
</ul>
<p>为了应对这些挑战，<code>pg_failover_slot</code> 插件能够自动同步主备节点之间的逻辑复制槽，确保故障转移时数据的连续性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pg_failover_slot-插件简介">pg_failover_slot 插件简介<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#pg_failover_slot-%E6%8F%92%E4%BB%B6%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><code>pg_failover_slot</code> 是专为 PostgreSQL 开发的一个插件，旨在解决逻辑复制槽无法在主备之间同步的问题。该插件通过在主节点和备节点之间同步逻辑复制槽，确保当备节点被提升为主节点时，它能够继续向下游订阅者发送数据变更，而不需要重新创建或手动干预。</p>
<p>插件的主要特性包括：</p>
<ul>
<li class="">自动复制槽同步：<code>pg_failover_slot</code> 可以在主备节点之间同步逻辑复制槽，确保备节点具备相应的复制槽记录。</li>
<li class="">简化的故障转移流程：在主备切换后，无需手动创建新的逻辑复制槽，保证订阅者能够立即获取新主节点上的数据变更。</li>
<li class="">高可用性支持：槽的同步，<code>pg_failover_slot</code> 提高了系统的容错能力和可用性，减少了宕机时的管理负担。</li>
</ul>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-1-53ecfb69e6a7f50bce8b282decc7e21b.png" width="864" height="488" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装和配置-pg_failover_slot-插件">安装和配置 pg_failover_slot 插件<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE-pg_failover_slot-%E6%8F%92%E4%BB%B6" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>为了在 IvorySQL 上使用 <code>pg_failover_slot</code> 插件，需要进行以下步骤。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="系统环境准备">系统环境准备<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E7%B3%BB%E7%BB%9F%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>假设您已经在生产环境中部署了 IvorySQL，并且已经配置了主备节点环境：</p>
<ul>
<li class="">
<p>主节点：primary_node</p>
</li>
<li class="">
<p>备节点：standby_node</p>
</li>
</ul>
<p>确保 IvorySQL 主备架构运行正常，且已创建逻辑复制槽，并使用高可用工具来管理故障转移过程和 VIP 管理实现漂移。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="下载并编译插件">下载并编译插件<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E4%B8%8B%E8%BD%BD%E5%B9%B6%E7%BC%96%E8%AF%91%E6%8F%92%E4%BB%B6" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>首先，从 GitHub 下载并编译 <code>pg_failover_slot</code> 插件：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">git clone</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">https://github.com/EnterpriseDB/pg_failover_slots.git</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cd pg_failover_slots</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">make</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">make install</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置-ivorysql">配置 IvorySQL<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E9%85%8D%E7%BD%AE-ivorysql" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>接下来，在主节点和备节点的 <code>postgresql.conf</code> 文件中添加 <code>pg_failover_slot</code> 插件到 <code>shared_preload_libraries</code>，并设置日志复制等级为 logical 或以上：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">wal_level = logical</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">shared_preload_libraries = 'pg_failover_slots'</span><br></span></code></pre></div></div>
<p>确保主库已创建物流复制槽，此为必要条件。</p>
<p>在备库配置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">hot_standby_feedback = on</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">primary_slot_name = ‘slot_name’</span><br></span></code></pre></div></div>
<p>这一设置使数据库在启动时加载插件。完成配置后，重启主节点和备节点的 IvorySQL 实例：</p>
<p><code>pg_ctl restart -D $PGDATA</code></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-2-83d5d38eedd6114d5719ff38e071c2af.png" width="945" height="155" class="img_ev3q"></p>
<p>启动成功后，查看进程可看到 <code>pg_failover_slot worker</code> 的子进程，并且 <code>show shared_preload_libraries</code> 可查看到有 <code>pg_failover_slots</code> 的信息，即插件生效。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建逻辑复制槽">创建逻辑复制槽<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E5%88%9B%E5%BB%BA%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%A7%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>使用 1521 端口进行 Oracle 模式连接，并主节点上创建带有兼容 Oracle 字段的表 <code>t_ora_like</code>、<code>test3</code>，下图显示模式为 Oracle 模式，显示 Oracle 属性字段 <code>varchar2</code> 的表 <code>t_ora_like</code>，作为基础测试表，旨在测试插件与 Oracle 兼容属性间的契合度。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-3-aa4674fda19d7d800886c5acc52a2859.png" width="1011" height="360" class="img_ev3q"></p>
<p>然后在主节点上创建一个发布：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE PUBLICATION my_publication FOR TABLE test3;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CREATE PUBLICATION my_publication2 FOR TABLE t_ora_like;</span><br></span></code></pre></div></div>
<p>此时，当有订阅方通过 VIP 订阅此发布，会创建相应的逻辑复制槽，<code>pg_failover_slot</code> 插件将自动同步该复制槽到备节点。您无需手动在备节点上创建复制槽。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-4-e45d81ecda1d95adfae725f93f212d7f.png" width="1010" height="185" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-5-46fea2efa86671d55a34d3b43e6a3714.png" width="1010" height="223" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="同步逻辑复制槽">同步逻辑复制槽<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E5%90%8C%E6%AD%A5%E9%80%BB%E8%BE%91%E5%A4%8D%E5%88%B6%E6%A7%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>备节点会同步相应的逻辑复制槽。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-6-3769ad677d18e8caf96c8afab26bf583.png" width="1017" height="192" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="故障转移与复制槽恢复">故障转移与复制槽恢复<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E6%95%85%E9%9A%9C%E8%BD%AC%E7%A7%BB%E4%B8%8E%E5%A4%8D%E5%88%B6%E6%A7%BD%E6%81%A2%E5%A4%8D" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><code>pg_failover_slot</code> 插件在主备节点上配置完成，它将自动管理逻辑复制槽的同步和故障转移。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="故障转移流程">故障转移流程<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E6%95%85%E9%9A%9C%E8%BD%AC%E7%A7%BB%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>当主节点发生故障时，使用高可用工具进行故障转移，备节点将被提升为新的主节点，VIP 漂移到新节点。<code>pg_failover_slot</code> 插件会确保新主节点恢复并接管逻辑复制槽。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="验证复制槽状态">验证复制槽状态<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E9%AA%8C%E8%AF%81%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%8A%B6%E6%80%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在新的主节点上检查复制槽是否已经恢复：</p>
<p><code>SELECT * FROM pg_replication_slots;</code></p>
<p>新主节点上已经存在原先在旧主节点上创建的逻辑复制槽。这意味着下游订阅者可以继续从新主节点获取数据变更，确保逻辑复制的无缝衔接。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-7-4c2c734b3eed4b940627e2c4a8cf5219.png" width="1017" height="191" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="订阅者同步">订阅者同步<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E8%AE%A2%E9%98%85%E8%80%85%E5%90%8C%E6%AD%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>下游订阅者无需任何额外操作，它们会通过 VIP 自动从新主节点接收更新，无需重新配置订阅。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-8-9fb7e911ff37cf9ab2e1beef2f6a1ddc.png" width="1021" height="563" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="img" src="https://ivorysql.org/zh-cn/assets/images/20241127-9-05f93243c234577ce9e843196aa3d2c1.png" width="520" height="342" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="最佳实践和注意事项">最佳实践和注意事项<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E5%92%8C%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>在使用 <code>pg_failover_slot</code> 插件时，以下最佳实践可以帮助您更好地管理和维护逻辑复制槽的高可用性：</p>
<ul>
<li class="">合理配置复制槽上限：在高并发或大规模复制场景中，确保 <code>max_replication_slots</code> 参数配置合理。IvorySQL 的 <code>postgresql.conf</code> 文件中的这一参数需要根据工作负载的复杂性进行调整，以避免复制槽过载。</li>
<li class="">定期监控复制槽状态：使用 <code>pg_stat_replication_slots</code> 视图定期检查复制槽的状态，确保在主备节点之间的同步过程中没有出现延迟或丢失。结合高可用工具进行自动化故障转移，可以实现主备节点的自动化切换，VIP 的管理和漂移。<code>pg_failover_slot</code> 插件与高可用工具配合使用时，可以确保复制槽在故障转移过程中的无缝接管。</li>
<li class="">性能优化与监控：逻辑复制在高并发时可能会对系统性能造成一定压力，因此推荐定期监控系统的 I/O 性能和 CPU 利用率，必要时调优系统配置。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://ivorysql.org/zh-cn/blog/ivorysql-ha-zero-loss-logical-replication-slots#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL 与 <code>pg_failover_slot</code> 插件为高可用环境中的逻辑复制提供了强大的支持。通过自动同步主备节点间的逻辑复制槽，<code>pg_failover_slot</code> 解决了故障转移后需要重新初始化复制槽的难题，显著提升了逻辑复制的稳定性和可用性。</p>
<p>对于需要无缝故障转移且不希望因复制槽问题导致下游订阅者丢失数据的用户来说，<code>pg_failover_slot</code> 是一种必不可少的工具。它简化了逻辑复制槽的管理流程，减少了数据库维护的复杂性，为高可用环境中的数据一致性保驾护航。</p>
<p>通过本文中的步骤，可以在 IvorySQL 中配置并使用 <code>pg_failover_slot</code> 插件，确保您的逻辑复制环境在主备切换时始终保持高效运行。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="High Availability" term="High Availability"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PGCon2022 会议回顾｜IvorySQL 项目的技术讲解]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-pgcon2022</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-pgcon2022"/>
        <updated>2022-06-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[2022 年渥太华时间 5 月 26 日瀚高北美研究院负责人 Grant Zhou 在会上发表 IvorySQL 项目的技术讲解。本次会议内容主要介绍了我们是谁、IvorySQL 是什么、IvorySQL 的关键功能点、社区贡献指南、开发者指南等。重点介绍了基于 PostgreSQL 14，IvorySQL 在 PostgreSQL 基础之上添加了一些令人兴奋的功能点！！]]></summary>
        <content type="html"><![CDATA[<p>2022 年渥太华时间 5 月 26 日瀚高北美研究院负责人 Grant Zhou 在会上发表 IvorySQL 项目的技术讲解。本次会议内容主要介绍了我们是谁、IvorySQL 是什么、IvorySQL 的关键功能点、社区贡献指南、开发者指南等。<strong>重点介绍了基于 PostgreSQL 14，IvorySQL 在 PostgreSQL 基础之上添加了一些令人兴奋的功能点！！</strong></p>
<p><strong>IvorySQL 在 PostgreSQL 的基础上增加的主要功能特点包括</strong>：</p>
<ul>
<li class="">
<p>Oracle 兼容包</p>
</li>
<li class="">
<p>Oracle 兼容 PL/iSQL 过程语言</p>
</li>
<li class="">
<p>GUC 在 Oracle 和 PostgreSQL 模式之间切换</p>
</li>
<li class="">
<p>Oracle 兼容各种 DDL 操作的语法</p>
</li>
<li class="">
<p>Oracle 兼容的日期/时间函数</p>
</li>
<li class="">
<p>内置 Orafce (<a href="https://github.com/orafce/orafce" target="_blank" rel="noopener noreferrer" class="">https://github.com/orafce/orafce</a>)</p>
</li>
</ul>
<p>更多功能特性描述，可参阅<a href="https://www.ivorysql.org/zh-CN/releases-page%E7%9A%84%E5%8F%91%E5%B8%83%E8%AF%B4%E6%98%8E%E3%80%82" target="_blank" rel="noopener noreferrer" class="">https://www.ivorysql.org/zh-CN/releases-page的发布说明。</a></p>
<p>大家可以通过 IvorySQL 产品路线图（<a href="https://github.com/IvorySQL/IvorySQL/issues%EF%BC%89%E5%AE%9A%E6%9C%9F%E6%9F%A5%E7%9C%8BGitHub%E4%B8%AD%E7%9A%84%E9%97%AE%E9%A2%98%E9%80%89%E9%A1%B9%E5%8D%A1%E5%8F%AF%E8%8E%B7%E5%BE%97%E6%9C%80%E6%96%B0%E7%9A%84%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8%E3%80%82" target="_blank" rel="noopener noreferrer" class="">https://github.com/IvorySQL/IvorySQL/issues）定期查看GitHub中的问题选项卡可获得最新的功能列表。</a></p>
<p><strong>bilibili 视频讲解链接</strong>：</p>
<p><a href="https://www.bilibili.com/video/BV17U4y1y7nZ?spm_id_from=333.999.list.card_archive.click" target="_blank" rel="noopener noreferrer" class="">PGCon2022 会议回顾|IvorySQL 项目的技术讲解_哔哩哔哩_bilibili</a></p>
<p>因为时差的原因，有许多小伙伴没有看到，小助理特意为大家整理好了会议视频内容以及<strong>中文 PPT 材料</strong>，有需要的小伙伴们，<strong>关注公众号，添加小助理微信即可获得。</strong></p>
<hr>
<blockquote>
<p>通过订阅邮件列表加入 IvorySQL 社区：</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
<li class="">官方微信公众号：<strong>IvorySQL开源数据库社区</strong></li>
</ul>
<p><strong>_欢迎在<a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a>给我们一个 <!-- -->⭐<!-- --> _</strong></p>
</blockquote>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="PGCon2022" term="PGCon2022"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 功能点介绍--Package（包）]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-packages</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-packages"/>
        <updated>2022-05-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[IvorySQL 是一个开源项目，该项目的核心目标之一是提供 oracle 兼容功能，以便在 IvorySQL 数据库服务器上使用 oracle 代码。]]></summary>
        <content type="html"><![CDATA[<p>IvorySQL 是一个开源项目，该项目的<strong>核心目标之一是提供 oracle 兼容功能</strong>，以便在 IvorySQL 数据库服务器上使用 oracle 代码。</p>
<p>在 PostgreSQL 之上提供 Oracle 兼容是一项多维任务。 从提供与 Oracle 兼容的 SQL 语法到添加对 PostgreSQL 中缺失或行为不同的数据类型的支持。 Oracle 兼容性的<strong>主要核心之一是在 PostgreSQL 中提供兼容的过程语言 PL（procedural language），它在功能和语法上与 Oracle 的 PL/SQL 兼容</strong>。</p>
<p>为此，<strong>IvorySQL 添加了一种新的 PL 语言 PL/iSQL，它接受、理解和执行 PL/SQL 语法</strong>。 如您所知，Oracle PL/SQL 的核心特性之一是 PACKAGES（包）。Package（包）是 Oracle 中的一个模式对象，它包含一组相关功能的定义，是 Oracle 使用最广泛的特性之一。</p>
<p>因此，本文将介绍 Package（包），并举例说明<strong>如何用 IvorySQL 创建、使用和销毁 Oracle 样式的包</strong>。</p>
<h1>包（Package）</h1>
<p>那么什么是 Package(包)？ 包是 PL/iSQL 代码的分组，按逻辑程序单元划分。 换句话说，一个包可以被认为是相关函数、过程、变量或游标的集合，这个集合可以通过通用公共名称来访问。</p>
<p>IvorySQL 内置 PL/iSQL 语言，可以接受、理解和执行 PL/SQL 代码。包使用相同的语言，并且有两个主要组件。</p>
<ul>
<li class=""><strong>包规范（Specification）</strong></li>
</ul>
<p>包规范列出了可以从包外部访问的所有项目,例如函数、过程、变量和游标。这也称为公共规范。</p>
<ul>
<li class=""><strong>包体（Body）</strong></li>
</ul>
<p>包体包含包规范中列出的所有函数和过程的实现。除此之外，它还可以实现更多的功能、过程或其他元素。</p>
<p>这些不在包规范中的元素将被视为包的私有成员，并且只能在包内引用它们。 不允许外部访问。</p>
<p>包体也可以有一个特殊的代码块，称为初始化块。 这是一个特殊的块，因为这个块在每个会话中只执行一次，在包第一次被访问的最开始。</p>
<p>让我们看一些代码示例，看看包是如何运行的。</p>
<h1>示例</h1>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="通用示例">通用示例<a href="https://ivorysql.org/zh-cn/blog/ivorysql-packages#%E9%80%9A%E7%94%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>首先让我们设置兼容模式，这样我们就可以访问 IvorysSQL 数据库中可用的 Oracle 兼容特性。</p>
<p>SET compatible_mode TO oracle;</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE TABLE books (</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id     INT, </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    title  VARCHAR2(100), </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    author VARCHAR2(100),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    price  NUMBER);</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (10, 'The Hobbit', 'J. R. R. Tolkien', 10.0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (11, 'Winnie-the-Pooh', 'A. A. Milne', 5.0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (12, 'Peter Pan', 'James Matthew Barrie', 4.0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (13, 'Charlie and the Chocolate Factory', 'Roald Dahl', 5.0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (14, 'SThe Jungle Book', 'Rudyard Kipling', 9.0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INSERT INTO books VALUES (15, 'The Little White Bird', 'James Matthew Barrie', 3.0);</span><br></span></code></pre></div></div>
<p>让我们来创建一个简单的包。这个包声明了一个游标来列出所有可用的图书，并包含一些子程序来列出、添加和删除书籍。同时，它还声明了一些私有变量来计数和保存图书信息。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE mybooks AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    CURSOR      booksinfo IS SELECT * from BOOKS;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE list_books;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FUNCTION add_book(title VARCHAR2(100), author VARCHAR2(100), </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         price NUMBER) RETURN bool;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE remove_book(book_title VARCHAR2(100));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# /</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CREATE PACKAGE</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE BODY mybooks AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    -- declare private variables</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    bookinfo    booksinfo%rowtype; </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    books_count INT;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE list_books AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        OPEN booksinfo;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO 'Book Info:';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        LOOP</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            FETCH booksinfo into bookinfo;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            EXIT WHEN NOT FOUND;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RAISE INFO '  Name    = %', bookinfo.title;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RAISE INFO '  Author  = %', bookinfo.author;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RAISE INFO '  Price   = %', bookinfo.price;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RAISE INFO '------------------------------';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        END LOOP;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO 'Total Books   = %', books_count;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        CLOSE booksinfo;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FUNCTION add_book(title VARCHAR2(100), author VARCHAR2(100),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        price NUMBER) RETURN bool AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        INSERT INTO BOOKS VALUES (</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            books_count + 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            title,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            author,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            price);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        books_count := books_count + 1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RETURN true;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        EXCEPTION WHEN OTHERS THEN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RETURN false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE remove_book(book_title VARCHAR2(100)) AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        DELETE FROM BOOKS WHERE title = book_title;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        EXCEPTION WHEN OTHERS THEN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            RAISE INFO 'Book % not found', book_title;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-- initializer block</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BEGIN         </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    books_count := 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    SELECT count(*) INTO books_count</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        FROM BOOKS;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# /</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CREATE PACKAGE BODY</span><br></span></code></pre></div></div>
<p>让我们检验这些数据。这匿名块试图访问该包的私有成员，这将会导致错误。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=# DECLARE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$#   nbooks int := 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$#     nbooks := mybooks.books_count;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$#     RAISE INFO 'Total Books   = %', nbooks;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# /</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2022-05-26 16:35:32.328 PKT [63554] ERROR:  package private variable ("mybooks.books_count") is not accessible</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre></div></div>
<p>让我们使用包的子程序列出所有可用的书籍。 <code>list_books</code>  <code>mybooks</code></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=# BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$#     mybooks.list_books;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql$# /</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Book Info:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Name    = The Hobbit</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Author  = J. R. R. Tolkien</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Price   = 10</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  ------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Name    = Winnie-the-Pooh</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Author  = A. A. Milne</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:    Price   = 3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">....</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">....</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Total Books   = 6</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">DO</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=#</span><br></span></code></pre></div></div>
<p>让我们使用包的子程序添加一本新书。 <code>add_book</code> <code>mybooks </code></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">DECLARE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  added bool;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    added := mybooks.add_book('The Cat in the Hat', 'Dr. Seuss', 10);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    IF added = TRUE THEN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO 'new book added';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END IF;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="删除包">删除包<a href="https://ivorysql.org/zh-cn/blog/ivorysql-packages#%E5%88%A0%E9%99%A4%E5%8C%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>可以使用以下命令删除包体或完成包：</p>
<ul>
<li class="">DROP PACKAGE BODY [package name]</li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=# DROP PACKAGE BODY mybooks;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">DROP PACKAGE BODY</span><br></span></code></pre></div></div>
<ul>
<li class="">DROP PACKAGE [package name]</li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=# DROP PACKAGE mybooks;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">DROP PACKAGE</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="具有不同权限的包调用">具有不同权限的包调用<a href="https://ivorysql.org/zh-cn/blog/ivorysql-packages#%E5%85%B7%E6%9C%89%E4%B8%8D%E5%90%8C%E6%9D%83%E9%99%90%E7%9A%84%E5%8C%85%E8%B0%83%E7%94%A8" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>我们将创建两个具有调用者和定义者权限的包，并查看结果以了解它们之间的区别。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; SELECT current_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> current_user </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(1 row)</span><br></span></code></pre></div></div>
<p>--创建具有 INVOKER 权限的包</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE pkg_invrights AUTHID CURRENT_USER AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE BODY pkg_invrights AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE curr_user AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO 'Current User: %', current_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/</span><br></span></code></pre></div></div>
<p>--创建一个具有 DEFINER 权限的包</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE pkg_defrights AUTHID DEFINER AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CREATE OR REPLACE PACKAGE BODY pkg_defrights AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    PROCEDURE curr_user AS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    BEGIN</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        RAISE INFO 'Current User: %', current_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">END;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/</span><br></span></code></pre></div></div>
<p>让我们先查看具有调用程序权限的包。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; CALL pkg_invrights.curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Current User: ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CALL</span><br></span></code></pre></div></div>
<p>让我们来看看具有定义权限的包。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; CALL pkg_defrights.curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Current User: ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CALL</span><br></span></code></pre></div></div>
<p>让我们切换到另一个名为 ivuser 的用户。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; \c ivorysql ivuser;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">You are now connected to database "ivorysql" as user "ivuser".</span><br></span></code></pre></div></div>
<p>让我们先看看具有调用程序权限的包。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; CALL pkg_invrights.curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Current User: ivuser</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CALL</span><br></span></code></pre></div></div>
<p>让我们看看具有定义权限的包。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=&gt; CALL pkg_defrights.curr_user;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">INFO:  Current User: ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CALL</span><br></span></code></pre></div></div>
<h1>总结</h1>
<p>如上所示，当调用具有调用者权限（pkg_invrights）的包时，它使用的是调用该包的用户的特权。但是，当调用（pkg_defrights）时，它仍然使用包所有者的特权。</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Oracle Package" term="Oracle Package"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL--Linux环境源码编译安装]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-linux</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-linux"/>
        <updated>2022-05-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[IvorySQL可以在Linux, OSX, Unix和Windows平台上构建，与PostgreSQL的编译安装基本上是一样的。本文对基于Linux的系统上编译源代码的步骤进行说明。]]></summary>
        <content type="html"><![CDATA[<p>IvorySQL可以在Linux, OSX, Unix和Windows平台上构建，与PostgreSQL的编译安装基本上是一样的。本文对基于Linux的系统上编译源代码的步骤进行说明。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一准备工作">一、准备工作<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E4%B8%80%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-获取-ivorysql-源码">1.1 获取 IvorySQL 源码<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#11-%E8%8E%B7%E5%8F%96-ivorysql-%E6%BA%90%E7%A0%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>Windows或Linux，只要安装了git，都可以使用git下载：</p>
<p>git clone <a href="https://github.com/IvorySQL/IvorySQL.git" target="_blank" rel="noopener noreferrer" class="">https://github.com/IvorySQL/IvorySQL.git</a></p>
<p>git clone <a href="https://gitee.com/IvorySQL/IvorySQL.git" target="_blank" rel="noopener noreferrer" class="">https://gitee.com/IvorySQL/IvorySQL.git</a></p>
<p>或者直接去github或gitee下载都可以：</p>
<p><a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">https://github.com/IvorySQL/IvorySQL</a></p>
<p><a href="https://gitee.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">https://gitee.com/IvorySQL/IvorySQL</a></p>
<p>github会有点慢，能用则用，不行就改用gitee。</p>
<p>截至本稿，IvorySQL的最新发布版本是1.2，于2022年2月28日发布。</p>
<p><img decoding="async" loading="lazy" alt="L" src="https://ivorysql.org/zh-cn/assets/images/L-aa-a866b566063dee5b4d47772d8ad6e1d9.png" width="756" height="214" class="img_ev3q"></p>
<p>本文使用的源码版本也是IvorySQL 1.2。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-安装依赖包">1.2 安装依赖包<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#12-%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96%E5%8C%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>要从源代码编译IvorySQL，必须确保系统上有可用的先决条件包。
执行以下命令安装相关包：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">sudo yum install -y bison-devel readline-devel zlib-devel openssl-devel wget</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">sudo yum groupinstall -y 'Development Tools'</span><br></span></code></pre></div></div>
<p><strong>说明：“Development Tools”包含了gcc，make，flex，bison。</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二编译安装">二、编译安装<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E4%BA%8C%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>前面通过获取的源码在文件夹IvorySQL里，接下来我们就进入这个文件夹进行操作。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-配置">2.1 配置<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#21-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>Root用户执行以下命令进行配置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">./configure</span><br></span></code></pre></div></div>
<p><strong>说明：由于没有提供--prefix，默认安装在/usr/local/pgsql。</strong></p>
<p>指定安装路径，如“/usr/local/ivorysql/ivorysql-1.2”：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">./configure --prefix=/usr/local/ivorysql/ivorysql-1.2</span><br></span></code></pre></div></div>
<p><strong>注意：我们要记住指定的目录，因为系统查不出已经编译安装的程序在哪。</strong></p>
<p>更多configure参数通过“./configure --help”查看。还可以查看PostgreSQL手册。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-编译安装">2.2 编译安装<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#22-%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>配置完成后，执行make进行编译：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">make</span><br></span></code></pre></div></div>
<p>要在安装新编译的服务之前使用回归测试测试一下，以下命令均可：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">make check</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">make check-world</span><br></span></code></pre></div></div>
<p>然后安装：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">make install</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三初始化数据库服务">三、初始化数据库服务<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E4%B8%89%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>我们这里只是简单配置一下，能本地和远程连接就可以了。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-创建操作系统用户">3.1 创建操作系统用户<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#31-%E5%88%9B%E5%BB%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%94%A8%E6%88%B7" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>用户root会话下，新建用户 ivorysql：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/usr/sbin/groupadd ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/usr/sbin/useradd -g ivorysql ivorysql -c "IvorySQL1.2 Server"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">passwd ivorysql</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-创建数据目录">3.2 创建数据目录<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#32-%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E7%9B%AE%E5%BD%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>接下来需要创建数据目录并修改权限。在root会话下执行以下命令。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /ivorysql/1.2/data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">chown -R ivorysql.ivorysql /ivorysql/1.2/</span><br></span></code></pre></div></div>
<p><strong>注意：这里没按RPM安装将数据目录放置到“/var/lib/ivorysql/ivorysql-1/data”。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="33-环境变量">3.3 环境变量<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#33-%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>切换到用户ivorysql，修改文件“/home/ ivorysql /.bash_profile”，配置环境变量：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">umask 022</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">export LD_LIBRARY_PATH=/usr/local/pgsql/lib:$LD_LIBRARY_PATH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">export PATH=/usr/local/pgsql/bin:$PATH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">export PGDATA=/ivorysql/1.2/data</span><br></span></code></pre></div></div>
<p>使环境变量在当前ivorysql用户会话中生效：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">source .bash_profile</span><br></span></code></pre></div></div>
<p>也可以重新登录或开启一个新的用户ivorysql的会话。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="34-设置防火墙">3.4 设置防火墙<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#34-%E8%AE%BE%E7%BD%AE%E9%98%B2%E7%81%AB%E5%A2%99" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>如果开启了防火墙，还需要将端口5333开放：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">firewall-cmd --zone=public --add-port=5333/tcp --permanent</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firewall-cmd --reload</span><br></span></code></pre></div></div>
<p><strong>说明：默认端口是5333，如果不开放该端口，外部客户端通过ip连接会失败。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="35-初始化">3.5 初始化<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#35-%E5%88%9D%E5%A7%8B%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>在用户ivorysql下，简单执行initdb就可以完成初始化：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">initdb</span><br></span></code></pre></div></div>
<p><strong>说明：initdb操作与PostgreSQL一样，可以按照PG的习惯去初始化。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="36-启动数据库">3.6 启动数据库<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#36-%E5%90%AF%E5%8A%A8%E6%95%B0%E6%8D%AE%E5%BA%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>使用pg_ctl启动数据库服务：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl start</span><br></span></code></pre></div></div>
<p>查看状态，启动成功：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl status</span><br></span></code></pre></div></div>
<p>pg_ctl: server is running (PID: 29549)</p>
<p>/usr/local/pgsql/bin/postgres</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四配置服务">四、配置服务<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E5%9B%9B%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>这里只是简单配置一下，能本地和远程连接就可以了</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-客户端验证">4.1 客户端验证<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#41-%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>修改 /ivorysql/1.2/data/pg_hba.conf，追加以下内容：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">host    all             all             0.0.0.0/0               trust</span><br></span></code></pre></div></div>
<p><strong>注意：这里是trust，就是说可以免密登录。</strong></p>
<p>执行以下命令加载配置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl reload</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-基本参数">4.2 基本参数<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#42-%E5%9F%BA%E6%9C%AC%E5%8F%82%E6%95%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>通过psql连接数据库：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">psql</span><br></span></code></pre></div></div>
<p>修改监听地址：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">alter system set listen_addresses = '*';</span><br></span></code></pre></div></div>
<p><strong>说明：默认是监听在127.0.0.1，主机外是连不上服务的。</strong></p>
<p>重启服务使设置生效：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pg_ctl restart</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="43-守护服务">4.3 守护服务<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#43-%E5%AE%88%E6%8A%A4%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>创建service文件：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">touch /usr/lib/systemd/system/ivorysql.service</span><br></span></code></pre></div></div>
<p>编辑内容如下：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[Unit]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Description=IvorySQL 1.2 database server</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Documentation=https://www.ivorysql.org</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Requires=network.target local-fs.target</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">After=network.target local-fs.target</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[Service]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Type=forking</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">User=ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Group=ivorysql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Environment=PGDATA=/ivorysql/1.2/data/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OOMScoreAdjust=-1000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ExecStart=/usr/local/pgsql/bin/pg_ctl start -D ${PGDATA}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ExecStop=/usr/local/pgsql/bin/pg_ctl stop -D ${PGDATA}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ExecReload=/usr/local/pgsql/bin/pg_ctl reload -D ${PGDATA}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">TimeoutSec=0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[Install]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WantedBy=multi-user.target</span><br></span></code></pre></div></div>
<p><strong>说明：service的写法有很多，在生产环境使用时需谨慎，请多次重复测试。</strong></p>
<p>停止pg_ctl启动的数据库服务，启用systemd服务并启动：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl enable --now ivorysql.service</span><br></span></code></pre></div></div>
<p>IvorSQL数据库服务操作命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl start ivorysql.service			--启动数据库服务</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl stop ivorysql.service				--停止数据库服务</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl restart ivorysql.service			--重启数据库</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl status ivorysql.service			--查看数据库状态</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl reload ivorysql.service			--可以满足部分数据库配置修改完后生效</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五客户端链接数据库">五、客户端链接数据库<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E4%BA%94%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%93%BE%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>连接IvorySQL数据库服务的客户端工具和PostgreSQL的一样。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-psql-连接">5.1 psql 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#51-psql-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>操作系统用户ivorysql会话下连接：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[ivorysql@Node02 ~]$ psql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">psql (15devel)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Type "help" for help.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=#</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-dbeaver-连接">5.2 DBeaver 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#52-dbeaver-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>DBeaver是一个功能比较强大的开源工具，连接配置如下：</p>
<p><img decoding="async" loading="lazy" alt="L" src="https://ivorysql.org/zh-cn/assets/images/L-bb-b44bbdc5453c56e00b193be3eb80e806.png" width="520" height="364" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-瀚高-developer-连接">5.3 瀚高 developer 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#53-%E7%80%9A%E9%AB%98-developer-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>瀚高developer是瀚高自主研发的一个工具，除了可以支持瀚高数据库，还支持PostgreSQL以及IvorySQL数据库。连接配置如下：</p>
<p><img decoding="async" loading="lazy" alt="L" src="https://ivorysql.org/zh-cn/assets/images/L-cc-afd5419a1cafecaa55fb8d90f5efa2be.png" width="536" height="519" class="img_ev3q"></p>
<p>如果想使用该工具，请关注公众号加入微信群“IvorySQL中国技术交流群”咨询。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六卸载">六、卸载<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E5%85%AD%E5%8D%B8%E8%BD%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>编译安装就用编译卸载的方式卸载。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="61-备份数据">6.1 备份数据<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#61-%E5%A4%87%E4%BB%BD%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>数据目录在“/ivorysql/1.2/data”下，所以我们将该目录保护好就可以，最好停止数据库服务后做备份。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="62-编译卸载">6.2 编译卸载<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#62-%E7%BC%96%E8%AF%91%E5%8D%B8%E8%BD%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>Root会话下切到源码目录下，分别执行以下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">make uninstall</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">make clean</span><br></span></code></pre></div></div>
<p>删除残余目录和文件：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl disable ivorysql.servicemake					--禁用服务</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">mv /usr/lib/systemd/system/ivorysql.service /tmp/		--服务文件移到/tmp，删除也可以</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rm -fr /usr/local/pgsql									--删除残留安装目录</span><br></span></code></pre></div></div>
<p>还有用户ivorysql以及对应的环境变量，可以根据情况是否清理。</p>
<p>剩下的就是数据目录“/ivorysql/1.2/data”了，请务必做好备份再做处理。</p>
<p>还有安装的依赖包，可根据情况决定是否卸载。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="七后记">七、后记<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E4%B8%83%E5%90%8E%E8%AE%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ul>
<li class="">
<p>更细化的操作，可参照PostgreSQL的相关内容。</p>
</li>
<li class="">
<p>大家还可以参考IvorySQL源码下自带文档：<a href="https://github.com/IvorySQL/IvorySQL/blob/master/README.md" target="_blank" rel="noopener noreferrer" class="">/root/IvorySQL/README.md</a>。</p>
</li>
<li class="">
<p>也可以打开网站链接：<a href="https://gitee.com/IvorySQL/IvorySQL/blob/master/README.md%E3%80%82" target="_blank" rel="noopener noreferrer" class="">https://gitee.com/IvorySQL/IvorySQL/blob/master/README.md。</a></p>
</li>
<li class="">
<p>有任何问题，欢迎大家到IvorySQL官方社区仓库：github.com/IvorySQL/IvorySQL 提交issue。</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="关于ivorysql">关于IvorySQL<a href="https://ivorysql.org/zh-cn/blog/ivorysql-linux#%E5%85%B3%E4%BA%8Eivorysql" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL项目是一个具有广泛生态基础和中国特色的PG开源衍生项目，是瀚高公司设计研发的一款具备强大Oracle兼容能力的开源数据库。具备高兼容性和高可用性，并致力于遵守open-source ways。</p>
<p><strong>社区仓库</strong>：github.com/IvorySQL/IvorySQL</p>
<p><strong>CSDN</strong>: IvorySQL</p>
<p><strong>开源中国</strong>：IvorySQL</p>
<p><strong>墨天轮</strong>：IvorySQL</p>
<p>通过订阅邮件列表加入IvorySQL社区：</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
<li class=""><strong>官方微信公众号：IvorySQL开源数据库社区</strong></li>
</ul>
<p>***还有，别忘了在<a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a>给我们一个 <!-- -->⭐<!-- --> ***</p>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Linux，PostgreSQL" term="Linux，PostgreSQL"/>
        <category label="Join Us" term="Join Us"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL--YUM 源安装]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-yum</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-yum"/>
        <updated>2022-05-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[通过 YUM 源安装软件]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="通过-yum-源安装软件">通过 YUM 源安装软件<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E9%80%9A%E8%BF%87-yum-%E6%BA%90%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>下面我们以操作系统Centos7.9环境为例，看看如何安装IvorySQL数据库。先介绍最简单的YUM源安装。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-安装-yum-源">1.1 安装 YUM 源<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#11-%E5%AE%89%E8%A3%85-yum-%E6%BA%90" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>下载地址：<a href="https://yum.highgo.ca/ivorysql.html" target="_blank" rel="noopener noreferrer" class="">https://yum.highgo.ca/ivorysql.html</a></p>
<p>点击图中按钮【DOWNLOAD REPO RPM】下载ivorysql-release-1.0-1.noarch.rpm并传到Centos7.9：</p>
<p><img decoding="async" loading="lazy" alt="yum" src="https://ivorysql.org/zh-cn/assets/images/yum-a-04c6327693f128106183af7771070b9b.png" width="361" height="242" class="img_ev3q"></p>
<p>或者在Centos7上使用wget下载：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">wget https://yum.highgo.ca/dists/ivorysql-rpms/repo/ivorysql-release-1.0-1.noarch.rpm</span><br></span></code></pre></div></div>
<p>安装ivorysql-release-1.0-1.noarch.rpm：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">rpm -ivh ivorysql-release-1.0-1.noarch.rpm</span><br></span></code></pre></div></div>
<p>安装后，将创建YUM源配置文件：/etc/yum.repos.d/ivorysql.repo。</p>
<p>搜索查看相关安装包：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yum search ivorysql</span><br></span></code></pre></div></div>
<p>搜索结果说明见表1：</p>
<p>​                                                                                                         表1 YUM源说明</p>
<table><thead><tr><th><strong>序号</strong></th><th><strong>包名</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>1</td><td><a href="https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-1.2-1.rhel7.x86_64.rpm" target="_blank" rel="noopener noreferrer" class="">ivorysql1.x86_64</a></td><td>IvorySQL 客户端程序和库文件</td></tr><tr><td>2</td><td><a href="https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-contrib-1.2-1.rhel7.x86_64.rpm" target="_blank" rel="noopener noreferrer" class="">ivorysql1-contrib.x86_64</a></td><td>随IvorySQL发布的已贡献的源代码和二进制文件</td></tr><tr><td>3</td><td>ivorysql1-devel.x86_64</td><td>IvorySQL开发头文件和库</td></tr><tr><td>4</td><td>ivorysql1-docs.x86_64</td><td>IvorySQL的额外文档</td></tr><tr><td>5</td><td><a href="https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-libs-1.2-1.rhel7.x86_64.rpm" target="_blank" rel="noopener noreferrer" class="">ivorysql1-libs.x86_64</a></td><td>所有IvorySQL客户端所需的共享库</td></tr><tr><td>6</td><td>ivorysql1-llvmjit.x86_64</td><td>对IvorySQL的即时编译支持</td></tr><tr><td>7</td><td>ivorysql1-plperl.x86_64</td><td>用于IvorySQL的过程语言Perl</td></tr><tr><td>8</td><td>ivorysql1-plpython3.x86_64</td><td>用于IvorySQL的过程语言Python3</td></tr><tr><td>9</td><td>ivorysql1-pltcl.x86_64</td><td>用于IvorySQL的过程语言Tcl</td></tr><tr><td>10</td><td><a href="https://yum.highgo.ca/dists/ivorysql-rpms/1/redhat/rhel-7-x86_64/ivorysql1-server-1.2-1.rhel7.x86_64.rpm" target="_blank" rel="noopener noreferrer" class="">ivorysql1-server.x86_64</a></td><td>创建和运行IvorySQL服务器所需的程序</td></tr><tr><td>11</td><td>ivorysql1-test.x86_64</td><td>随IvorySQL发布的测试套件</td></tr><tr><td>12</td><td>ivorysql-release.noarch</td><td>瀚高基础软件股份有限公司的Yum源配置RPM包</td></tr></tbody></table>
<p><strong>说明：1、2、5、10是RPM包安装需要的，超链接可以单独下载。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-安装-ivorysql">1.2 安装 IVORYSQL<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#12-%E5%AE%89%E8%A3%85-ivorysql" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>要安装数据库服务，需要安装ivorysql1-server。
在用户root会话下执行以下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yum install -y ivorysql1-server</span><br></span></code></pre></div></div>
<p><strong>安装清单：</strong></p>
<p>ivorysql1-server.x86_64 0:1.2-1.rhel7</p>
<p><strong>依赖安装：</strong></p>
<ul>
<li class="">
<p>ivorysql1.x86_64 0:1.2-1.rhel7			ivorysql1-contrib.x86_64 0:1.2-1.rhel7</p>
</li>
<li class="">
<p>ivorysql1-libs.x86_64 0:1.2-1.rhel7		libicu.x86_64 0:50.2-4.el7_7</p>
</li>
<li class="">
<p>libtirpc.x86_64 0:0.2.4-0.16.el7			libxslt.x86_64 0:1.1.28-6.el7</p>
</li>
<li class="">
<p>python3.x86_64 0:3.6.8-18.el7			python3-libs.x86_64 0:3.6.8-18.el7</p>
</li>
<li class="">
<p>python3-pip.noarch 0:9.0.3-8.el7		python3-setuptools.noarch 0:39.2.0-10.el7</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-已安装目录">1.3 已安装目录<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#13-%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9B%AE%E5%BD%95" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>表2对YUM安装过程产生的文件目录进行说明。</p>
<p>​                                                                 表2 安装目录文件说明</p>
<table><thead><tr><th><strong>序号</strong></th><th><strong>文件路径</strong></th><th><strong>描述</strong></th></tr></thead><tbody><tr><td>1</td><td>/usr/local/ivorysql/ivorysql-1</td><td>软件安装目录</td></tr><tr><td>2</td><td>/var/lib/ivorysql/ivorysql-1/data</td><td>数据目录（默认）</td></tr><tr><td>3</td><td>/usr/bin/ivorysql-1-setup</td><td>帮助系统管理员进行基本的数据库集群管理</td></tr><tr><td>4</td><td>/usr/lib/systemd/system/ivorysql-1.service</td><td>守护服务</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="14-rpm安装">1.4 RPM安装<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#14-rpm%E5%AE%89%E8%A3%85" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>顺便说一下RPM安装，需要按这个顺序安装：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yum install -y libicu libxslt python3					--先安装依赖</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rpm -ivh ivorysql1-libs-1.2-1.rhel7.x86_64.rpm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rpm -ivh ivorysql1-1.2-1.rhel7.x86_64.rpm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rpm -ivh ivorysql1-contrib-1.2-1.rhel7.x86_64.rpm --nodeps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rpm -ivh ivorysql1-server-1.2-1.rhel7.x86_64.rpm</span><br></span></code></pre></div></div>
<p>所以，使用YUM安装还是很方便的。如果没条件，就单独下载按这个顺序安装吧。</p>
<p>下载地址：<a href="https://yum.highgo.ca/ivorysql.html" target="_blank" rel="noopener noreferrer" class="">https://yum.highgo.ca/ivorysql.html</a></p>
<p><img decoding="async" loading="lazy" alt="yum" src="https://ivorysql.org/zh-cn/assets/images/yum-b-e7662c15d043ef4c0d252a5394927bb5.png" width="378" height="474" class="img_ev3q"></p>
<p>点击【BROWSE REPOSITORY-1】找到对应的包下载即可（注意：官网没提供依赖包）。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="初始化数据库">初始化数据库<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E6%8D%AE%E5%BA%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL数据库默认初始化以及启停等操作比较简单。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-默认初始化">2.1 默认初始化<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#21-%E9%BB%98%E8%AE%A4%E5%88%9D%E5%A7%8B%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>我们可以在root用户下，执行以下命令使用系统默认参数来初始化：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/usr/local/ivorysql/ivorysql-1/bin/ivorysql-1-setup initdb</span><br></span></code></pre></div></div>
<p><strong>说明：由于没有提供SERVICE_NAME，默认会读ivorysql-1。</strong></p>
<p>启用并启动服务：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl enable --now ivorysql-1.service</span><br></span></code></pre></div></div>
<p>ivorysql-1-setup的用法：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql-1-setup {initdb|check_upgrade|upgrade} [SERVICE_NAME]</span><br></span></code></pre></div></div>
<p><strong>说明：该命令的详细用法，执行命令“ivorysql-1-setup --help”查看。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-自定义初始化">2.2 自定义初始化<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#22-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%9D%E5%A7%8B%E5%8C%96" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>假如我们有个需求，要制定数据文件路径（/ivorysql/1.2/data/）和端口号（5866），那我们就可以定制初始化。</p>
<p>根据默认的服务文件“/usr/lib/systemd/system/ivorysql-1.service”在相同目录下复制一个新的“ivorysql-5866.service”：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">cp /usr/lib/systemd/system/ivorysql-1.service /usr/lib/systemd/system/ivorysql-5866.service</span><br></span></code></pre></div></div>
<p>修改添加以下内容：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Environment=PGDATA=/ivorysql/1.2/data/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Environment=PGPORT=5866</span><br></span></code></pre></div></div>
<p>指定SERVICE_NAME为ivorysql-5866来初始化：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/usr/local/ivorysql/ivorysql-1/bin/ivorysql-1-setup initdb ivorysql-5866</span><br></span></code></pre></div></div>
<p>启用并启动服务：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl enable --now ivorysql-5866.service</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-常用服务操作">2.3 常用服务操作<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#23-%E5%B8%B8%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%93%8D%E4%BD%9C" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>IvorSQL数据库服务操作命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl start ivorysql-1.service				--启动数据库服务</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl stop ivorysql-1.service				--停止数据库服务</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl restart ivorysql-1.service			--重启数据库</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl status ivorysql-1.service			--查看数据库状态</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">systemctl reload ivorysql-1.service			--可以满足部分数据库配置修改完后生效</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置数据库服务">配置数据库服务<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>我们这里只是简单配置一下，能本地和远程连接就可以了。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-客户端验证">3.1 客户端验证<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#31-%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>修改 /var/lib/ivorysql/ivorysql-1/data/pg_hba.conf，追加以下内容：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">host    all             all             0.0.0.0/0               scram-sha-256</span><br></span></code></pre></div></div>
<p>执行以下命令加载配置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl reload ivorysql-1.service</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-基本参数">3.2 基本参数<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#32-%E5%9F%BA%E6%9C%AC%E5%8F%82%E6%95%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>切换到用户ivorysql：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">su - ivorysql</span><br></span></code></pre></div></div>
<p>通过psql连接数据库：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">psql</span><br></span></code></pre></div></div>
<p>修改监听地址，便于远程连接顺便改一下ivorysql的密码：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">alter system set listen_addresses = '*';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">alter user ivorysql password '666666';</span><br></span></code></pre></div></div>
<p><strong>说明：用户ivorysql是没有密码的，如果不修改密码，可以修改客户端验证方式为trust，来免密登录。</strong></p>
<p>退回root用户，重启服务使设置生效：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl restart ivorysql-1.service</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="防火墙">防火墙<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E9%98%B2%E7%81%AB%E5%A2%99" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>如果开启了防火墙，还需要将端口5333开放：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">firewall-cmd --zone=public --add-port=5333/tcp --permanent</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">firewall-cmd --reload</span><br></span></code></pre></div></div>
<p><strong>说明：刚初始化好的ivorysql服务默认端口是5333，如果不开放该端口，外部客户端通过ip连接会失败。</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端连接数据库">客户端连接数据库<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9E%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>连接IvorySQL数据库服务的客户端工具和PostgreSQL的一样。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-psql-连接">4.1 psql 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#41-psql-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>操作系统用户ivorysql会话下连接：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[root@Node02 ~]# su - ivorysql </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Last login: Wed Apr 27 23:58:57 CST 2022 on pts/0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-bash-4.2$ psql</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">psql (14.2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Type "help" for help.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ivorysql=#</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-dbeaver-连接">4.2 DBeaver 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#42-dbeaver-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>DBeaver是一个功能比较强大的开源工具，连接配置如下：</p>
<p><img decoding="async" loading="lazy" alt="yum" src="https://ivorysql.org/zh-cn/assets/images/yum-c-b44bbdc5453c56e00b193be3eb80e806.png" width="520" height="364" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="43-瀚高-developer-连接">4.3 瀚高 developer 连接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#43-%E7%80%9A%E9%AB%98-developer-%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>瀚高developer是瀚高自主研发的一个工具，除了可以支持瀚高数据库，还支持PostgreSQL以及IvorySQL数据库。连接配置如下：</p>
<p><img decoding="async" loading="lazy" alt="yum" src="https://ivorysql.org/zh-cn/assets/images/yum-d-afd5419a1cafecaa55fb8d90f5efa2be.png" width="536" height="519" class="img_ev3q"></p>
<p>如果想使用该工具，请关注公众号加入微信群“IvorySQL中国技术交流群”咨询。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="卸载">卸载<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E5%8D%B8%E8%BD%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>由于我们是通过yum安装的，要卸载建议也使用yum，尽量不要使用rpm，可能会造成卸载不完整。当然了，也可以根据yum安装清单去卸载。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-备份数据">5.1 备份数据<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#51-%E5%A4%87%E4%BB%BD%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>数据目录在/var/lib/ivorysql/ivorysql-1/data下，所以我们将该目录保护好就可以，最好停止服务，做个备份。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-yum-卸载">5.2 YUM 卸载<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#52-yum-%E5%8D%B8%E8%BD%BD" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h3>
<p>首先停止数据库服务：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl stop ivorysql-1.service</span><br></span></code></pre></div></div>
<p>先使用“yum history list”确定yum安装的事务ID：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[root@Node02 ~]# yum history list</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Loaded plugins: fastestmirror</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ID     | Login user               | Date and time    | Action(s)      | Altered</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-------------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     5 | root &lt;root&gt;              | 2022-04-27 12:38 | Install        |   11  &lt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     4 | root &lt;root&gt;              | 2022-03-26 16:08 | Install        |   35 &gt; </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     3 | root &lt;root&gt;              | 2022-03-26 16:07 | I, U           |   19   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     2 | root &lt;root&gt;              | 2022-03-26 16:07 | I, U           |   73   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     1 | System &lt;unset&gt;           | 2022-03-26 15:59 | Install        |  299   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">history list</span><br></span></code></pre></div></div>
<p>可以看到ID为5的是执行安装的事务。执行命令卸载（需将XX替换为“5”）：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yum history undo XX</span><br></span></code></pre></div></div>
<p>也可以使用下面命令来卸载：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yum remove ivorysql-server</span><br></span></code></pre></div></div>
<p>但该命令卸载并不彻底，只卸载了2个依赖，还有8个依赖未能卸载。可以根据是否保留这些依赖而决定是否使用这种方式卸载。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="后记">后记<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E5%90%8E%E8%AE%B0" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ul>
<li class="">
<p>更细化的操作，可以参照postgresql的操作。例如，用initdb直接初始化。</p>
</li>
<li class="">
<p>大家还可以参考IvorySQL自带文档： /usr/share/doc/ivorysql1-1.2/README.rpm-dist。</p>
</li>
<li class="">
<p>有任何问题，欢迎大家到IvorySQL官方社区仓库：github.com/IvorySQL/IvorySQL 提交issue。</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="关于ivorysql">关于IvorySQL<a href="https://ivorysql.org/zh-cn/blog/ivorysql-yum#%E5%85%B3%E4%BA%8Eivorysql" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL项目是一个具有广泛生态基础和中国特色的PG开源衍生项目，是瀚高公司设计研发的一款具备强大Oracle兼容能力的开源数据库。具备高兼容性和高可用性，并致力于遵守open-source ways。</p>
<p><strong>社区仓库</strong>：github.com/IvorySQL/IvorySQL</p>
<p><strong>CSDN</strong>: IvorySQL</p>
<p><strong>开源中国</strong>：IvorySQL</p>
<p><strong>墨天轮</strong>：IvorySQL</p>
<hr>
<blockquote>
<p>通过订阅邮件列表加入IvorySQL社区：</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
<li class=""><strong>官方微信公众号：IvorySQL开源数据库社区</strong></li>
</ul>
<p>***还有，别忘了在<a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a>给我们一个 <!-- -->⭐<!-- --> ***</p>
</blockquote>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="YUM， PostgreSQL" term="YUM， PostgreSQL"/>
        <category label="Join Us" term="Join Us"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL亮相于PostgresConf SV 2022 硅谷Postgres大会]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-pgconf-sv-2022</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-pgconf-sv-2022"/>
        <updated>2022-04-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[硅谷Postgres会议是西海岸最大的PG会议，也是美国乃至全球Postgres年度重要会议之一，于2022年4月7日至8日（PDT）在美国加利福尼亚州圣何塞希尔顿酒店召开。作为面向全球PostgreSQL技术专家、从业者、爱好者的年度技术交流活动，硅谷会议致力于汇集和讨论关于人、Postgres和数据间的关系！会议与主办地硅谷一样极具包容和公平精神，这里汇集了最优秀的演讲者、听众和赞助商，所有人努力为全球Postgres生态系统创造发展机会。]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>硅谷Postgres会议是西海岸最大的PG会议，也是美国乃至全球Postgres年度重要会议之一，于2022年4月7日至8日（PDT）在美国加利福尼亚州圣何塞希尔顿酒店召开。作为面向全球PostgreSQL技术专家、从业者、爱好者的年度技术交流活动，硅谷会议致力于汇集和讨论关于人、Postgres和数据间的关系！会议与主办地硅谷一样极具包容和公平精神，这里汇集了最优秀的演讲者、听众和赞助商，所有人努力为全球Postgres生态系统创造发展机会。</p>
<p>会议现场人数大概有200多人，是疫情以来聚集人数最多的一次线下会议。</p>
<p><strong>社区核心人员Bruce Momjian出席</strong>，会议由PostgresConf,Joshua D.Drake, Jim Mlodgenski 等组织。来自中国、美国、加拿大、巴西、西班牙、德国、印度、巴基斯坦等多个国家的人员参与。</p>
</blockquote>
<p><strong>瀚高北美研究院兼中国PostgreSQL分会国际顾问委员会秘书长Grant Zhou作为唯一中国代表，将携IvorySQL项目亮相本次会议。</strong></p>
<p>以下是由<strong>IvorySQL开源数据库社区</strong>为您带来的硅谷Postgres两日会议简报。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="部分演讲议题">部分演讲议题<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pgconf-sv-2022#%E9%83%A8%E5%88%86%E6%BC%94%E8%AE%B2%E8%AE%AE%E9%A2%98" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><strong>IvorySQL--一个基于PostgreSQL的兼容Oracle的开源数据库 --by GRANT ZHOU</strong></p>
<p>有很多用户需要将他们的应用程序从Oracle迁移到开放源码的Postgres，但是为了支持新的数据库，用户经常需要重新开发应用程序，这很不方便。如果有一个基于Postgres的数据库，并且兼容大多数Oracle语法和函数，对客户来说就太方便了。然而官方的Postgres项目不接受这种代码提交。毕竟，Postgres是Postgres, Oracle是Oracle。因此，IvorySQL项目团队创建一个Oracle兼容的数据库。</p>
<p>本演讲中介绍了如何基于PG实现与Oracle语法兼容的数据库，并介绍IvorySQL项目。这个项目是一个开源项目(Apache 2.0)，由Highgo软件领导，目前已经发布了基于PostgreSQL 14.2版本的IvorySQL 1.2。</p>
<p>同时欢迎大家为这个开源的侧重Oracle兼容性的数据库——IvorySQL做出贡献。</p>
<p><strong>非关系型Postgres --by Bruce Momjian</strong></p>
<p>Postgres一直对关系存储提供强大的支持。然而，在许多情况下，关系存储要么效率低下，要么限制过度。这个演讲展示了Postgres扩展到支持非关系存储的许多方式，特别是在一个数据库字段中存储和索引多个值(甚至是不相关的值)的能力。这种存储可以提高效率和访问的简单性，还可以避免实体-属性-值(eav)存储的缺点。演讲涵盖多个字段多值存储的例子，包括数组、范围类型、几何图形、全文搜索、xml、json和记录。</p>
<p><strong>数字权力和隐私：21世纪的关注--by Andres Arrieta</strong></p>
<p>30多年来，电子前沿基金会一直在保护和争取我们的公民自由。在这30年里发生了很多事情:我们与互联网的关系从根本上发生了改变，然而，在很多方面，我们对互联网如何运作的理解仍然停滞不前。如今，互联网已经成为我们生活中不可或缺的核心部分，我们越来越依赖互联网。虽然我们比以往任何时候都更容易接触到互联网提供的众多礼物，但决策者和执法机构对互联网如何运作的理解仍然滞后。在此期间，电子前沿基金会及其使命已经涵盖了技术带来的好或坏的许多方面，并帮助保护那些受其影响的人，同时确保一个光明的未来，通过创新改善我们的生活。</p>
<p>Andres Arrieta向大家介绍了我们的一些工作、一些关切的领域以及Andres Arrieta认为将有助于我们朝着更美好的未来努力的一些事情。主要是关于数据隐私和消费者权利的理论视角。讨论了隐私的不同方面以及保护个人隐私的选项。</p>
<p><strong>逻辑复制的过去、现在和未来--by Amit Kapila</strong></p>
<p>在这次演讲中，Amit Kapila讲述了逻辑复制在PostgreSQL中是如何发展的。这将解释最近的一些最近的主要增强，比如促进两阶段和正在进行的大型事务的逻辑复制。并分享了Amit Kapila对如何利用该技术为大型企业构建高度可伸缩和可用的数据库解决方案的看法。在那之后，还讨论了在PostgreSQL未来版本中在这个技术领域中讨论的一些重要增强。并且介绍如何增强这项技术，以便将数据从PostgreSQL迁移到其他数据库。</p>
<p><strong>现代原生云应用的传记--by Karthik Ranganathan</strong></p>
<p>现代云原生应用程序过着令人兴奋的生活 - 从它们在云中诞生，到处理巨大的计划外成功，再到在云中断中幸存下来并处理全球客户。在本次演讲中，Yugabyte 首席技术官 Karthik Ranganathan 从数据层的角度介绍了Yugabyte 如何处理双向表级复制和高可用性。</p>
<p><strong>Aurora的亚马逊Babelfish--by chandra pathivada</strong></p>
<p>现在奥罗拉的Babelfish已经上市了。这个演示是关于Babelfish如何帮助客户迁移SQL Server工作负载到Postgres。在这个演示中，chandra pathivada演示了什么是Babelfish, Aurora的内部结构，使用Babelfish的SQL Server dba的Aurora，以及应用程序迁移实验室。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="现场照片">现场照片<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pgconf-sv-2022#%E7%8E%B0%E5%9C%BA%E7%85%A7%E7%89%87" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="p" src="https://ivorysql.org/zh-cn/assets/images/p-one-8381d4902bab3d647c986ea97959d3d6.png" width="1702" height="1276" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="p" src="https://ivorysql.org/zh-cn/assets/images/p-two-746f70e28fa4ac9ec6ba39735237c125.png" width="686" height="513" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="p" src="https://ivorysql.org/zh-cn/assets/images/p-three-b379f047807b2c626e7dfd21f0e7ac03.png" width="566" height="411" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="p" src="https://ivorysql.org/zh-cn/assets/images/p-four-4d1f6770fc82a4887ce6a361073aaf2e.png" width="628" height="510" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="p" src="https://ivorysql.org/zh-cn/assets/images/p-five-3a3dfe8a09cbbba27e4dea6738fbd23f.png" width="1702" height="1276" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="更多详情内容">更多详情内容<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pgconf-sv-2022#%E6%9B%B4%E5%A4%9A%E8%AF%A6%E6%83%85%E5%86%85%E5%AE%B9" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><strong>2022年硅谷Postgres会议官方网址：</strong>
<a href="https://postgresconf.org/conferences/SV2022" target="_blank" rel="noopener noreferrer" class="">https://postgresconf.org/conferences/SV2022</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="关于ivorysql">关于IvorySQL<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pgconf-sv-2022#%E5%85%B3%E4%BA%8Eivorysql" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL项目是一个具有广泛生态基础和中国特色的PG开源衍生项目，是<strong>瀚高公司</strong>设计研发的一款具备强大Oracle兼容能力的开源数据库。
具备高兼容性和高可用性，并致力于遵守open-source ways。
IvorySQL社区欢迎并赞赏所有类型的贡献，期待您的加入！</p>
<hr>
<blockquote>
<p>通过订阅邮件列表加入IvorySQL社区：</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
<li class="">官方微信公众号：IvorySQL开源数据库社区</li>
</ul>
<p>***还有，别忘了在<a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a>给我们一个 <!-- -->⭐<!-- --> ***</p>
</blockquote>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="PostgresConf SV" term="PostgresConf SV"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Join Us" term="Join Us"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PostgresWorld网络研讨会|IvorySQL的深度探讨]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/ivorysql-pg-webinar</id>
        <link href="https://ivorySQL.org/zh-cn/blog/ivorysql-pg-webinar"/>
        <updated>2022-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Hi~各位朋友们，我们的PostgresWorld Webinars又回来啦！]]></summary>
        <content type="html"><![CDATA[<p>Hi~各位朋友们，我们的PostgresWorld Webinars又回来啦！</p>
<p>PostgreSQL在国内数据库的发展过程中承担了非常重要的角色，全球众多数据库产品选择PostgreSQL作为技术发展路线。但是<strong>应用程序从Oracle迁移到开源Postgres的问题成为了最大的阻碍</strong>，因此我们创建了IvorySQL开源项目，它是基于最新的PostgreSQL 14并具有强大Oracle兼容性的数据库。
然而我们为什么一定要做IvorySQL开源项目？它和Postgres、Oracle技术上有什么区别？本次网络研讨会邀您一起探讨。</p>
<p>本期网络研讨会由Grant Zhou带来《IvorySQL - 一个基于PostgreSQL的兼容Oracle的开源数据库》为主题的分享，共同探讨基于PG并兼容Oracle的开源数据库。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="嘉宾介绍">嘉宾介绍<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pg-webinar#%E5%98%89%E5%AE%BE%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p><strong>Grant Zhou</strong>目前居住在加拿大，他是瀚高北美研究院的负责人，并领导PostgreSQL公司开发团队，团队成员来自加拿大，中国和巴基斯坦。他同时担任PostgreSQL中国分会国际顾问委员会的秘书长，也很自豪能成为PostgresConf的组织者和亚洲联络人。他在阿尔卡特朗讯（诺基亚）公司工作了十多年，在高可用性、实时电信系统、数据库技术和Unix/Linux编程方面拥有丰富的经验。
2021年12月，该团队宣布了IvorySQL数据库的第一个可用版本，<strong>这是目前唯一一款基于PostgreSQL、兼容Oracle的开源数据库</strong>。2022年2月28日，基于PostgreSQL 14.2发布了IvorySQL 1.2。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="研讨会要点介绍">研讨会要点介绍<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pg-webinar#%E7%A0%94%E8%AE%A8%E4%BC%9A%E8%A6%81%E7%82%B9%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>有许多用户需要将他们的应用程序从Oracle迁移到开源Postgres，但是为了支持新的数据库，用户经常需要重新开发应用程序，这很不方便。如果有一个基于Postgres的数据库，并且与大多数Oracle语法和函数兼容，那么对于客户来说就太方便了。
但是，官方的Postgres项目不会接受这种代码提交。毕竟，Postgres是Postgres，Oracle是Oracle。
因此，我们创建了一个具有Oracle兼容功能的开源数据库项目。
本次演讲将介绍<strong>如何基于PG实现与Oracle语法兼容的数据库，详细介绍IvorySQL项目的研发过程</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="时间与链接">时间与链接<a href="https://ivorysql.org/zh-cn/blog/ivorysql-pg-webinar#%E6%97%B6%E9%97%B4%E4%B8%8E%E9%93%BE%E6%8E%A5" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<ul>
<li class="">活动时间：<strong>美国太平洋时间（PDT）3月31日 下午1点-2点 (北京时间凌晨4：00-5：00）进行</strong>，敬请关注。</li>
<li class="">参与注册网址：<a href="https://postgresconf.org/accounts/sign_up" target="_blank" rel="noopener noreferrer" class="">https://postgresconf.org/accounts/sign_up</a></li>
<li class="">观看链接：<a href="https://postgresconf.org/conferences/PostgresWorld-Webinars-2022/program/proposals/ivorysql-an-open-source-oracle-compatible-database-based-on-postgresql" target="_blank" rel="noopener noreferrer" class="">https://postgresconf.org/conferences/PostgresWorld-Webinars-2022/program/proposals/ivorysql-an-open-source-oracle-compatible-database-based-on-postgresql</a></li>
<li class="">也可添加小助理微信：IvorySQL_official，立即报名参与！</li>
</ul>
<hr>
<blockquote>
<p>Join the IvorySQL community by subscribing to mailing lists:</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
</ul>
<p><em><strong>Also, don't forget to give us a <!-- -->⭐<!-- --> on <a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a></strong></em></p>
</blockquote>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="PostgresWorld" term="PostgresWorld"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Join Us" term="Join Us"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[IvorySQL 已经来了]]></title>
        <id>https://ivorySQL.org/zh-cn/blog/IvorySQL</id>
        <link href="https://ivorySQL.org/zh-cn/blog/IvorySQL"/>
        <updated>2022-01-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Hello]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Hello" src="https://ivorysql.org/zh-cn/assets/images/Hello-banner-46adc27e2ab99f4a46ba52a46482515c.png" width="1400" height="425" class="img_ev3q"></p>
<p>正当全世界都在为节日打包行李，迎接新年的到来时，我们正努力工作，并为我们的团队从2021年初开始的项目做最后的润色。那天是12月15日，就在那天结束之前，我们得到了所有的绿灯，在清理桌子之前，我们默默地发布了IvorySQL的第一个版本。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ivorysql概览">IvorySQL概览<a href="https://ivorysql.org/zh-cn/blog/IvorySQL#ivorysql%E6%A6%82%E8%A7%88" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL是<strong>Apache 2.0</strong>许可的开源Oracle兼容PostgreSQL。IvorySQL的第一个版本源自PostgreSQL 14，它坚定地承诺始终保持100%的PostgreSQL兼容性，并可以直接替换PostgreSQL的最新版本。</p>
<p>IvorySQL在现有标准PostgreSQL配置参数的基础上添加了一个兼容的_db GUC。 <code>compatible_db</code> 是一个切换开关，用于在Oracle和PostgreSQL兼容模式之间切换。IvorySQL的第二大亮点是 <code>PL/iSQL</code> 支持oracle PL/SQL语法的过程语言。这两个新增功能在不破坏标准PostgreSQL兼容性的情况下，是IvorySQL的Oracle兼容性的核心。<code>compatible_db</code> 切换在Oracle和PostgreSQL中存在的函数和对象的行为，并以不同的方式运行，而<code>PL/iSQL</code> 为在最小的更改上运行IORYSQL的Oracle代码奠定了基础。</p>
<p>IvorySQL具有许多与Oracle兼容的功能，包括Oracle风格的<strong>PACKAGES</strong>, <strong>DATA Types</strong>, 和 <strong>Conversion Functions</strong>. 有关IvorySQL中Oracle兼容性功能的详细信息，请参阅 <em><a href="https://www.ivorysql.org/zh-CN/docs/intro" target="_blank" rel="noopener noreferrer" class="">IvorySQL文档</a></em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="我们致力于遵循开源方式的原则">我们致力于遵循开源方式的原则<a href="https://ivorysql.org/zh-cn/blog/IvorySQL#%E6%88%91%E4%BB%AC%E8%87%B4%E5%8A%9B%E4%BA%8E%E9%81%B5%E5%BE%AA%E5%BC%80%E6%BA%90%E6%96%B9%E5%BC%8F%E7%9A%84%E5%8E%9F%E5%88%99" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>IvorySQL致力于遵守 <em><strong><a href="https://opensource.com/open-source-way" target="_blank" rel="noopener noreferrer" class="">open-source ways</a></strong></em> 我们坚信建设一个健康、包容的社区。我们坚持认为好的想法可以来自任何地方，最好的想法应该获胜。只有包含不同的观点，我们才能做出最佳决策。虽然IvorySQL的第一个版本主要关注Oracle兼容性功能，但未来的路线图和功能集将由社区以开源的方式确定。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="为ivorysql做贡献">为IvorySQL做贡献<a href="https://ivorysql.org/zh-cn/blog/IvorySQL#%E4%B8%BAivorysql%E5%81%9A%E8%B4%A1%E7%8C%AE" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>有很多方法可以帮助IvorySQL。您可以通过提供文档更新和文档翻译来做出贡献。如果你有设计技能，你可以为IvorySQL网站项目做出贡献。
测试IvorySQL和报告问题，通过发布bug修复或新功能的pull请求，或回答邮件列表上的问题，是对IvorySQL项目做出贡献的一些方式，IvorySQL社区欢迎并赞赏所有类型的贡献。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="快速开始">快速开始<a href="https://ivorysql.org/zh-cn/blog/IvorySQL#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B" class="hash-link" aria-label="直接链接到标题" title="直接链接到标题" translate="no">​</a></h2>
<p>所有与IvorySQL相关的项目，包括数据库服务器、网站和文档，都通过Github托管和管理。您可以通过IvorySQL <a href="https://github.com/IvorySQL/" target="_blank" rel="noopener noreferrer" class="">Github page</a>下载源代码或发布的软件包.</p>
<p>浏览 <a href="http://www.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">http://www.ivorysql.org</a> 阅读项目文档和贡献指南。</p>
<hr>
<blockquote>
<p>通过订阅邮件列表加入IvorySQL社区：</p>
<ul>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/hackers.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Hackers List</a></strong></li>
<li class=""><strong><a href="https://lists.ivorysql.org/postorius/lists/general.ivorysql.org/" target="_blank" rel="noopener noreferrer" class="">Users List</a></strong></li>
</ul>
<p>***还有，别忘了在<a href="https://github.com/IvorySQL/IvorySQL" target="_blank" rel="noopener noreferrer" class="">Github</a>给我们一个 <!-- -->⭐<!-- --> ***</p>
</blockquote>]]></content>
        <author>
            <name>IvorySQL Team</name>
            <uri>https://github.com/ivorysql</uri>
        </author>
        <category label="IvorySQL" term="IvorySQL"/>
        <category label="Welcome" term="Welcome"/>
        <category label="Database" term="Database"/>
        <category label="Oracle Compatible" term="Oracle Compatible"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="Join Us" term="Join Us"/>
    </entry>
</feed>