스크립트
00:00:00事实证明,那些说“兄弟,所有东西用 Postgres 就对了”的开发者们
00:00:04在即将发布的 Postgres 19 中显得更加正确了,该版本包含了对图查询的原生支持
00:00:10这是一个非常酷的功能。所以在今天的视频中,我想介绍 Postgres 19 的所有重磅功能
00:00:16并深入探讨图查询,因为我认为它
00:00:21可能会从根本上改变我们设计查询和使用 Postgres 的方式。
00:00:30首先要介绍的是一个叫做 on conflict do select 的功能。如果你想插入一行数据,前提是它尚不存在
00:00:35并且无论是否存在你都想把这行数据作为结果返回,通常你需要
00:00:40两条查询来实现:一条 insert 和一条 select,这是一种非常常见的工作流程。所以在示例中
00:00:45我们说要向 users 的 email 和 name 插入数据,然后给出这些值,接着在
00:00:50末尾我们写上 on conflict for email do nothing returning star。Do nothing 在行已存在时不会返回任何内容
00:00:56所以你需要接着执行一个 select,但连在一起它们就不是原子的。而在 19 中你可以
00:01:03通过一个查询搞定。向 users 插入 email 和 name,然后写上 on conflict email do select
00:01:11returning star。如果你想在同一个查询中进行修改,我们可以写 insert into users,然后再次给出
00:01:16值,接着写 on conflict for the email do select for update returning id and name。由于这是一个单独的
00:01:23语句,它是原子的,你要么插入它,要么每次都选中它,这是一个
00:01:29非常普遍的用例,将会非常有用。接下来是图,但如果你喜欢这个内容,
00:01:34为什么不订阅 better stack 以了解科技领域的最新动态呢。如我之前所说,
00:01:39在我看来这是最重磅的功能。假设你有一个商店的常规模式,拥有客户、
00:01:44订单和产品,外加将它们串联起来的两张连接表,而你想知道某个特定的客户
00:01:50究竟买了哪个产品。在 SQL 中,这需要在所有五张表之间进行一连串的 join,虽然在这里
00:01:56还算可控,但面对更复杂的关联时,它很快就会变得非常难看。不过现在我们
00:02:02可以把所有这些作为一个图来查询,复杂的 join 语法现在可以变成一种全新的图语法。
00:02:08特别是对于复杂的 join,你会在这里看到巨大的优势。我们现在在数据库
00:02:14查看器里,你可以看到我们拥有所有的表:产品、订单、事件,还有
00:02:20客户,以及连接所有这些数据的透视表。我们有订单项
00:02:25和客户订单,现在让我们尝试对所有这些表运行查询。比如说,
00:02:30这里有个叫爱丽丝的用户,我想查出爱丽丝订购的所有东西。为了做到这一点,
00:02:35我得通过一堆不同的 join 查询来连接所有这些表。因此我会运行这个
00:02:41包含四个独立 join 语句的查询,虽然这不一定很难
00:02:46写,但非常丑陋。不过如果我们运行它,你可以看到爱丽丝订购的所有物品——
00:02:51机械键盘和人体工学鼠标。但现在我们可以使用图语法来极大地简化
00:02:57这一切。我们将用新的图语法替换所有这些,然后再次执行它,你就会
00:03:03发现我们得到了相同的记果,如果把这些排成一行,它读起来就会变得更轻松,你可以看到
00:03:07我们只是从客户到客户订单,再到订单、订单项,最后到产品。所以你
00:03:13基本上只需遵循这个简单的流程就能遍历整个图,依我来看这要容易阅读得多得多。
00:03:19如果你也想选择多个列,我们同样可以做到,我们在顶部有相同的
00:03:23图查询,但接着我们可以在底部定义列,然后选择我们想要显示的
00:03:27所有列,执行后我们就能在底部看到结果。现在,除非我们一开始就
00:03:32创建了图,否则这些都不会起作用。我用来生成该图的
00:03:37查询在这里,我们说 create property graph,然后给它起个名字 my shop,接着
00:03:42勾勒出顶点表,也就是客户、订单和产品,这些是
00:03:47真正持有数据的对象,然后我们有边表,这些是
00:03:52真正建立连接的对象,也就是我们的透视表,在我们的例子中就是客户订单和订单
00:03:57项。它的语法超级简单,我们说对于客户订单,源是客户,
00:04:02目标是订单;对于订单项,源是订单,目标是产品。有了这些,
00:04:08每当我们运行图查询时,postgres 就会知道这些关系是如何定义的。
00:04:14为了让它工作,你需要创建一个图,但这不会创建新表之类的内容,
00:04:19你只需指向你已有的五张表,其中真正持有数据的三张表变成
00:04:23顶点,两张连接表变成边,它的工作方式更像是一个视图,所以你先前的模式
00:04:29保持完全不变,你只是在上面获得了这个附加功能。所以在这里我们要
00:04:35说 create property graph,将其命名为 my shop,然后开始描述该关系
00:04:40是如何实际运作的,这就是我们为图做所有工作的地方,这意味着查询
00:04:45可以比各自的 join 语法精简得多。那么,这是 neo4j 的替代品吗?如果你想要一个
00:04:52图数据库是因为你需要图存储和遍历性能,那么不是,专用的图
00:04:58数据库可能仍然是更好的选择。但如果你想要它是因为在 sql 中编写 10 张表的 join
00:05:03既痛苦又丑陋,那么它绝对会让你受益,并且相比之下会好用得多。
00:05:09第三个新功能是 repack,这个功能旨在取回磁盘空间。postgres
00:05:15从不就地更新行,它会写入一个新版本并将旧版本留在后面,而 vacuum 仅仅
00:05:21将死空间标记为可重用,所以你的磁盘占用实际上永远不会下降。repack 会将整张表重写
00:05:27到一个没有浪费空间的新文件中,这才是把空间还给
00:05:33操作系统的方式。你其实已经可以通过 vacuum full 来做到这一点,但这会在整个重写过程中
00:05:38对表加锁,所以对于任何巨大的表你根本不会运行它,这也是为什么人们会安装
00:05:42像 pg repack 这样的扩展。但现在我们直接将其内置到了 postgres 中,在其中使用 concurrently 关键字
00:05:49就能在 repack 工作的同时保持表的可读写。不过这里需要注意的一点是,
00:05:54你需要有足够的可用磁盘空间来存放表的第二个副本及其所有索引,所以你需要
00:06:00备用空间来真正回收更多空间。所以这并不是 pg repack 的完全替代品,但对于
00:06:06普通表而言,它无需扩展就能完成工作。好了,接下来我们要对
00:06:1119 版本中的其余功能进行快速连珠炮式的介绍。首先是查询提示,postgres 决定如何实际运行你的
00:06:17查询,而且它可能会随着时间改变主意,所以一个用了一年都正常的查询突然变慢了,
00:06:22而你的代码没有任何改变。一个名为 pg plan advice 的新模块允许你在查询仍然很快时捕获执行计划
00:06:28并将其固定,这样它就会一直保持那种状态。jit 现在默认关闭了,postgres 会将繁重的查询
00:06:36编译为机器码,但它根据规划器的成本估算来决定何时费心去做,而发行说明
00:06:41指出这种成本计算实际上并不可靠,因此它会在那些实际上不需要它的
00:06:46查询上触发。此外,vacuum 现在可以使用多个工作线程并行清理你的索引,这样可以减少
00:06:52清理大表花费的时间。不过你确实需要自己开启这个功能。你知道当你添加一列
00:06:58去执行 select,然后又必须将同一列添加到 group by 中时,它会为你处理好这一切。
00:07:03并且 copy 关键字现在可以直接导出为 json,所以如果你一直在转储 csv 并在事后进行转换,
00:07:09你可以停止这么做了。这就是 postgres 19 beta 2 在 7 月份登陆的情况,最终版本
00:07:15预计在 9 月或 10 月左右发布,所以如果你运行的是任何旧版本,现在就值得把 beta 版拉下来
00:07:21并针对它进行测试。如果你想了解更多关于 postgres 的信息,你其实可以查看
00:07:25对 pg durable 的剖析,它将持久工作流直接放进了 postgres 中。我是来自
00:07:31betterstack 的 warren,感谢您的观看,我们下期再见