在 PostgreSQL 和 YugabyteDB 中需要创建连接并执行 SQL 来执行工作,并且无论工作单元有多小,任何工作请求都会有一定的延迟。为了获得最佳性能,选择适合所需性能的策略非常重要。
创建连接
在任何数据库(甚至是嵌入式数据库)中创建数据库连接都会增加延迟。对于嵌入式数据库(如 sqlite),开销似乎(并且现在)非常低,但仍保留数据库会话将比分叉进程来处理它具有更好的性能。
本文介绍了为后绿色SQL和汤字节数据库创建连接的延迟和解决方法。该文章的主要信息是:您应该使用应用程序连接池来保持和重用数据库连接,否则即使您有一个“外部”连接池(如pbouncer),您也会遭受更高的延迟。
连接池程序可以改善延迟,但它不会为您提供持久的连接应用程序连接池延迟,因为已建立的连接不需要再次创建连接来执行 SQL。
首次访问数据库
在 PostgreSQL 和 YugabyteDB 邮局主管启动后,与每个数据库的第一个连接将导致该会话重新创建存储全局数据库及其连接到的数据库的关系缓存的文件。
本文对此进行了更详细的解释。主要信息是:这在常用数据库中很可能不是问题,但是在构建PostgreSQL或YugabyteDB数据库集群用于测试的情况下,或者创建单个数据库进行测试的情况下,您必须知道第一个连接将显示更高的延迟,因此应该避免延迟计算。
再次目录
此时,已建立后greSQL或YugabyteDB连接,并准备执行其工作,因此可以执行用户SQL。这就是 SQL 可以在稳定延迟下执行的要点吗?
可悲的是,没有postgreSQL,因此是YugabyteDB,架构需要解析,重写,计划和执行阶段来执行SQL。重写和计划阶段需要数据库中的元数据来验证和优化要执行的 SQL。该元数据是数据库在其目录中存储的内容。
每个后端都在其专用内存中独立缓存目录数据。后端启动后,私有目录元数据足以让后端执行 SQL。这意味着它排除了有关数据库中的表和其他对象的任何目录数据。因此,当 SQL 执行对常规数据库对象的访问时,它必须首先从目录中获取 SQL 中涉及的所有对象的元数据,以便能够执行执行阶段。
加载元数据后,它将保留在后端缓存中。执行涉及为其缓存目录数据的对象执行 SQL 可以重用缓存的元数据。DDL 可能会使目录缓存失效。
那是什么意思?为了查看上述描述的效果,我正在使用我为这些测试创建的一个小实用程序:连接分析器(这是锈的源代码)。它非常简单地需要连接和SQL执行。
connection-profiler \
--url "host=192.168.66.100 port=5432 user=postgres password=postgres" \
--query 'select count(*) from t' \
--repeat-sql 5
create_connection 3052 us
------------------------------------------------------------
run nr: 1
total simple query 851 us
run nr: 2
total simple query 360 us
run nr: 3
total simple query 356 us
run nr: 4
total simple query 319 us
run nr: 5
total simple query 307 us
============================================================
复制
连接是花费最多时间的步骤。这显示了连接池的重要性。
然后,在同一会话中执行相同的SQL:“从t中选择计数(*)”,但SQL并不那么重要。这是 SQL 运行之间的时序差异。第一个执行(运行编号 1)比其他执行花费更多的时间。
但是,只是这些数字太少,无法绝对确定发生了什么。这些延迟可能是由各种事情引起的。上述执行是使用简单的查询协议进行的,该协议允许数据库一次性执行解析,重写,计划和执行所有这些步骤,从而将其作为单个步骤进行计时。
让我们通过使用扩展查询协议执行它来看看这一点:
connection-profiler \
--url "host=192.168.66.100 port=5432 user=postgres password=postgres" \
--query 'select count(*) from t' \
--repeat-sql 5 \
--protocol extended
create_connection 2636 us
------------------------------------------------------------
run nr: 1
parse+describe+sync 577 us
bind+execute+sync 581 us
total extended protocol 1204 us
run nr: 2
parse+describe+sync 247 us
bind+execute+sync 378 us
total extended protocol 668 us
run nr: 3
parse+describe+sync 284 us
bind+execute+sync 312 us
total extended protocol 650 us
run nr: 4
parse+describe+sync 204 us
bind+execute+sync 270 us
total extended protocol 507 us
run nr: 5
parse+describe+sync 242 us
bind+execute+sync 260 us
total extended protocol 537 us
============================================================
复制
Rust 连接为数据库端解析和重写执行网络往返(在客户端称为“parse”,与它在服务器端执行的两个阶段之一相同),并为计划和执行(称为绑定并在客户端执行)执行网络往返。
可见的是,解析和绑定+执行步骤在第一次执行时花费的时间要多得多。这并不是硬性证明这是因为加载目录条目,但很可能。特别是因为重复上述5次执行几次会产生合理的相等延迟。
如果您仔细研究了上面两个不同运行的数字,您会发现扩展协议的数字比简单查询协议更糟糕(具有更高的延迟)。这是因为我正在使用极简主义的SQL,这使得网络飞行时间导致延迟。如果将更多数据推送到数据库或从数据库拉取数据,则执行阶段的数据库时间将增加,从而减少网络中的相对时间。
结论
如果要将数据库连接与 PostgreSQL(因此 YugabyteDB)一起使用,并且确实获得一致的 SQL 响应时间,则需要具有专用的应用程序端连接池。
如果使用专用的应用程序端连接池,则如果后端未缓存数据库对象元数据,则 SQL 的响应时间仍会波动,因此必须加载这些元数据以允许后端执行执行 SQL 的步骤。后端不能在彼此之间共享其加载/缓存的目录数据。
如果后端中不存在所需的目录数据,则必须提取这些数据以允许处理 SQL,这会增加整体执行的延迟。上述示例显示了延迟的增加。加载目录数据的延迟影响与在执行阶段处理实际数据的时间有关。
这意味着,如果使用连接池,但不保持数据库客户端与单个数据库后端的连接,则在很多情况下执行 SQL 可能需要请求目录数据,从而增加延迟。
如果要针对自己的环境查看或测量此情况,请使用连接分析器进行旋转,并查看它如何适用于您的环境。
原文标题:PostgreSQL and YugabyteDB connections and SQL latency
原文作者:Frits Hoogland
原文地址:https://dev.to/yugabyte/postgresql-and-yugabytedb-connections-and-sql-latency-n6b