PostgreSQL的学习心得和知识总结(一百四十七)|深入理解PostgreSQL数据库之transaction chain的使用和实现


注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《PostgreSQL数据库内核分析》
2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》
3、PostgreSQL数据库仓库链接,点击前往
4、日本著名PostgreSQL数据库专家 铃木启修 网站主页,点击前往
5、参考书籍:《PostgreSQL中文手册》
6、参考书籍:《PostgreSQL指南:内幕探索》,点击前往
7、Using Transaction Chaining to Reduce Server Round-Trips,点击前往


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)
5、本文内容基于PostgreSQL master源码开发而成


深入理解PostgreSQL数据库之transaction chain的使用和实现

  • 文章快速说明索引
  • 功能使用背景说明
  • 功能实现源码分析
  • 源码调试案例分析



文章快速说明索引

学习目标:

做数据库内核开发久了就会有一种 少年得志,年少轻狂 的错觉,然鹅细细一品觉得自己其实不算特别优秀 远远没有达到自己想要的。也许光鲜的表面掩盖了空洞的内在,每每想到于此,皆有夜半临渊如履薄冰之感。为了睡上几个踏实觉,即日起 暂缓其他基于PostgreSQL数据库的兼容功能开发,近段时间 将着重于学习分享Postgres的基础知识和实践内幕。


学习内容:(详见目录)

1、深入理解PostgreSQL数据库之transaction chain的使用和实现


学习时间:

2024年07月01日 20:25:11


学习产出:

1、PostgreSQL数据库基础知识回顾 1个
2、CSDN 技术博客 1篇
3、PostgreSQL数据库内核深入学习


注:下面我们所有的学习环境是Centos8+PostgreSQL master+Oracle19C+MySQL8.0

postgres=# select version();
                                                  version                                                   
------------------------------------------------------------------------------------------------------------
 PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21), 64-bit
(1 row)

postgres=#

#-----------------------------------------------------------------------------#

SQL> select * from v$version;          

BANNER        Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
BANNER_FULL	  Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production Version 19.17.0.0.0	
BANNER_LEGACY Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
CON_ID 0


#-----------------------------------------------------------------------------#

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.06 sec)

mysql>

功能使用背景说明

使用 PostgreSQL 或任何关系数据库实现业务应用程序通常相当于执行一系列事务。给定事务以 COMMIT 还是 ROLLBACK 结束并不重要,因为在这两种情况下,下一个事务都会在前一个事务完成后立即开始。此外,对于大多数应用程序来说,前一个事务和下一个事务具有相似的特征,例如它们的 ISOLATION LEVEL。本质上,您最终得到的样式如下所示:

START TRANSACTION;
-- workload of 1st transaction
COMMIT;
START TRANSACTION;
-- workload of 2nd transaction
ROLLBACK;
START TRANSACTION;
-- workload of 3rd transaction
COMMIT;

在上面的 SQL 脚本中,您会看到三个后续事务和总共六个语句(每个事务两个语句),但您可以想象更长的事务序列。问题是:每个语句都需要单独的服务器往返才能执行。没有办法解决这个问题,即使三个示例事务为空(不包含任何语句),也没有什么区别。


监控连接状态

为了进行此实验,我们需要与同一 PostgreSQL 服务器建立两个单独的连接(例如,两个 psql 会话)。第一个连接使用 postgres 数据库,第二个连接使用demo数据库。

好了,现在我们可以在第一个连接上使用 pg_stat_activity(属于 pg_catalog 模式的内置视图)来询问 PostgreSQL 使用演示数据库的第二个连接的状态:

postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
 state
-------
 idle
(1 row)

如您所见,由于没有执行任何操作,因此该连接当前处于空闲状态。但是,如果我们在第二个连接上启动事务,我们可以看到连接的状态立即变为idle in transaction

demo=# START TRANSACTION;
START TRANSACTION
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
        state
---------------------
 idle in transaction
(1 row)

这证明 START TRANSACTION 语句导致了与服务器的往返,因为如果没有,第一个连接将无法看到第二个连接的状态变化。如果我们使用 COMMITROLLBACK 完成事务,情况也是一样的,在这种情况下,连接会立即恢复到空闲状态:

demo=*# COMMIT;
COMMIT
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
 state
-------
 idle
(1 row)

往返开销

长话短说,事务的开始和结束可能会带来巨大的开销。具体来说,如果满足以下任何条件:

  1. 往返服务器的时间很慢。通常,如果客户端和服务器之间的网络距离很远,情况就会如此。
  2. 许多事务的平均运行时间很短。这是因为对于较短的事务,开销占总运行时间的百分比较高。

那么,我们可以做些什么来减少开销并提高性能呢?


事务链

SQL 标准有一个由 PostgreSQL 实现的内置解决方案:AND CHAIN 参数。此参数可用于 COMMITROLLBACK 语句,并具有以下效果…

如果提供了 AND CHAIN 参数,则提交(或回滚)当前事务,此外,立即启动具有相同特征(例如,ISOLATION LEVEL)的后续事务。

因此,如果我们将其应用于原始示例,我们可以将服务器往返次数减少基本上 50%(从 n 减少到 n/2+1)。

START TRANSACTION;
-- workload of 1st transaction
COMMIT AND CHAIN;
-- workload of 2nd transaction
ROLLBACK AND CHAIN;
-- workload of 3rd transaction
COMMIT;

我们可以运行相同的实验来证明它按预期工作。我再次使用两个连接,一个使用 postgres 数据库,另一个使用演示数据库。最初,演示连接处于空闲状态,但是一旦我们开始新的事务,其状态就会更改为idle in transaction

demo=# START TRANSACTION;
START TRANSACTION
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
        state
---------------------
 idle in transaction
(1 row)

那么,如果demo连接执行 COMMIT AND CHAIN 语句会发生什么?正如我所说,PostgreSQL 立即启动后续事务,因此我们看不到状态变化。

demo=# COMMIT AND CHAIN;
COMMIT AND CHAIN
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
        state
---------------------
 idle in transaction
(1 row)

当我们执行 ROLLBACK AND CHAIN 时,我们得到完全相同的行为 — 没有明显的状态改变。

demo=# ROLLBACK AND CHAIN;
ROLLBACK AND CHAIN
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
        state
---------------------
 idle in transaction
(1 row)

最后,当我们发出正常的COMMITROLLBACK时,状态就会变回初始的空闲状态。

demo=# COMMIT;
COMMIT
postgres=# SELECT state FROM pg_stat_activity WHERE datname='demo';
 state
-------
 idle
(1 row)

功能实现源码分析

其语法格式如下:

// src/backend/parser/gram.y

/*****************************************************************************
 *
 *		Transactions:
 *
 *		BEGIN / COMMIT / ROLLBACK
 *		(also older versions END / ABORT)
 *
 *****************************************************************************/

TransactionStmt:
			ABORT_P opt_transaction opt_transaction_chain
				{
					TransactionStmt *n = makeNode(TransactionStmt);

					n->kind = TRANS_STMT_ROLLBACK;
					n->options = NIL;
					n->chain = $3;
					n->location = -1;
					$$ = (Node *) n;
				}
			...
			| COMMIT opt_transaction opt_transaction_chain
				{
					TransactionStmt *n = makeNode(TransactionStmt);

					n->kind = TRANS_STMT_COMMIT;
					n->options = NIL;
					n->chain = $3;
					n->location = -1;
					$$ = (Node *) n;
				}
			| ROLLBACK opt_transaction opt_transaction_chain
				{
					TransactionStmt *n = makeNode(TransactionStmt);

					n->kind = TRANS_STMT_ROLLBACK;
					n->options = NIL;
					n->chain = $3;
					n->location = -1;
					$$ = (Node *) n;
				}
			...
		;
		
TransactionStmtLegacy:
			...
			| END_P opt_transaction opt_transaction_chain
				{
					TransactionStmt *n = makeNode(TransactionStmt);

					n->kind = TRANS_STMT_COMMIT;
					n->options = NIL;
					n->chain = $3;
					n->location = -1;
					$$ = (Node *) n;
				}
		;

opt_transaction_chain:
			AND CHAIN		{ $$ = true; }
			| AND NO CHAIN	{ $$ = false; }
			| /* EMPTY */	{ $$ = false; }
		;

示例一,如下:

在这里插入图片描述
在这里插入图片描述


示例二,如下:

在这里插入图片描述
在这里插入图片描述


源码调试案例分析

接下来,我们调试一下 重点看一下上面的示例二,如下:

在这里插入图片描述

如上,begin READ ONLY;是在上图将guc参数transaction_read_only设置为真 XactReadOnly = true,函数堆栈,如下:

set_config_with_handle(const char * name, config_handle * handle, const char * value, GucContext context, GucSource source, Oid srole, GucAction action, _Bool changeVal, int elevel, _Bool is_reload) (\home\postgres\postgres\src\backend\utils\misc\guc.c:3758)
set_config_option(const char * name, const char * value, GucContext context, GucSource source, GucAction action, _Bool changeVal, int elevel, _Bool is_reload) (\home\postgres\postgres\src\backend\utils\misc\guc.c:3361)
SetPGVariable(const char * name, List * args, _Bool is_local) (\home\postgres\postgres\src\backend\utils\misc\guc_funcs.c:320)
standard_ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\utility.c:619)
ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\utility.c:523)
PortalRunUtility(Portal portal, PlannedStmt * pstmt, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\pquery.c:1158)
PortalRunMulti(Portal portal, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\pquery.c:1315)
PortalRun(Portal portal, long count, _Bool isTopLevel, _Bool run_once, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\pquery.c:791)
exec_simple_query(const char * query_string) (\home\postgres\postgres\src\backend\tcop\postgres.c:1274)
PostgresMain(const char * dbname, const char * username) (\home\postgres\postgres\src\backend\tcop\postgres.c:4680)
BackendMain(char * startup_data, size_t startup_data_len) (\home\postgres\postgres\src\backend\tcop\backend_startup.c:105)
postmaster_child_launch(BackendType child_type, char * startup_data, size_t startup_data_len, ClientSocket * client_sock) (\home\postgres\postgres\src\backend\postmaster\launch_backend.c:265)
BackendStartup(ClientSocket * client_sock) (\home\postgres\postgres\src\backend\postmaster\postmaster.c:3593)
ServerLoop() (\home\postgres\postgres\src\backend\postmaster\postmaster.c:1674)
PostmasterMain(int argc, char ** argv) (\home\postgres\postgres\src\backend\postmaster\postmaster.c:1372)
main(int argc, char ** argv) (\home\postgres\postgres\src\backend\main\main.c:197)

接下来,这里将直接INSERT,报错如下:

在这里插入图片描述

后续处理,如下:

在这里插入图片描述

此时的函数堆栈,如下:

AtEOXact_GUC(_Bool isCommit, int nestLevel)
AbortTransaction()
AbortCurrentTransactionInternal()
AbortCurrentTransaction()
PostgresMain(const char * dbname, const char * username)
BackendMain(char * startup_data, size_t startup_data_len)
postmaster_child_launch(BackendType child_type, char * startup_data, size_t startup_data_len, ClientSocket * client_sock)
BackendStartup(ClientSocket * client_sock)
ServerLoop()
PostmasterMain(int argc, char ** argv)
main(int argc, char ** argv)

注:如上 在INSERT报错之后,该事务对应的上述GUC被重置,如下:

// src/backend/utils/misc/guc.c

/*
 * Do GUC processing at transaction or subtransaction commit or abort, or
 * when exiting a function that has proconfig settings, or when undoing a
 * transient assignment to some GUC variables.  (The name is thus a bit of
 * a misnomer; perhaps it should be ExitGUCNestLevel or some such.)
 * During abort, we discard all GUC settings that were applied at nesting
 * levels >= nestLevel.  nestLevel == 1 corresponds to the main transaction.
 *  
 * 在事务或子事务提交或中止时,或在退出具有 proconfig 设置的函数时,或在撤消对某些 GUC 变量的临时分配时,执行 GUC 处理
 * (因此,这个名字有点用词不当;也许应该是 ExitGUCNestLevel 或类似的名字)
 * 在中止期间,我们会丢弃在嵌套级别 >= nestLevel 处应用的所有 GUC 设置
 * nestLevel == 1 对应于主事务
 */
void
AtEOXact_GUC(bool isCommit, int nestLevel);

于是在接下来的commit and chain;中,XactReadOnly仍是假,如下:

在这里插入图片描述

此时函数堆栈,如下:

EndTransactionBlock(_Bool chain)
standard_ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc)
ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc)
PortalRunUtility(Portal portal, PlannedStmt * pstmt, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, QueryCompletion * qc) 
PortalRunMulti(Portal portal, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc)
PortalRun(Portal portal, long count, _Bool isTopLevel, _Bool run_once, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc)
exec_simple_query(const char * query_string)
...

接下来,我们调试一下上面的示例二的另一种情况,因为当前会话已经设置该GUC参数为真(将要被rollback或者commit的事务),接下来的rollback and chain的处理 如下:

在这里插入图片描述

UserAbortTransactionBlock(_Bool chain) (\home\postgres\postgres\src\backend\access\transam\xact.c:4262)
standard_ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc)
ProcessUtility(PlannedStmt * pstmt, const char * queryString, _Bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment * queryEnv, DestReceiver * dest, QueryCompletion * qc)
PortalRunUtility(Portal portal, PlannedStmt * pstmt, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, QueryCompletion * qc)
PortalRunMulti(Portal portal, _Bool isTopLevel, _Bool setHoldSnapshot, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc)
PortalRun(Portal portal, long count, _Bool isTopLevel, _Bool run_once, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc)
exec_simple_query(const char * query_string)
...

在UserAbortTransactionBlock函数中的处理,如下:

s->blockState: TBLOCK_INPROGRESS -> TBLOCK_ABORT_PENDING
s->chain: false -> true

然后进入如下的处理逻辑:

CommitTransactionCommandInternal()
CommitTransactionCommand()
finish_xact_command()
exec_simple_query(const char * query_string)
...
			/*
			 * Here we were in a perfectly good transaction block but the user
			 * told us to ROLLBACK anyway.  We have to abort the transaction
			 * and then clean up.
			 */
		case TBLOCK_ABORT_PENDING:
			AbortTransaction();
			CleanupTransaction();
			s->blockState = TBLOCK_DEFAULT;
			if (s->chain)
			{
				StartTransaction();
				s->blockState = TBLOCK_INPROGRESS;
				s->chain = false;
				RestoreTransactionCharacteristics(&savetc);
			}
			break;

首先进入AbortTransaction函数,因为在这种情况下guc_stack_list != NIL,在如下的堆栈处理中 该参数XactReadOnly被置为假:

AtEOXact_GUC(_Bool isCommit, int nestLevel)
AbortTransaction()
CommitTransactionCommandInternal()
CommitTransactionCommand()
finish_xact_command()
exec_simple_query(const char * query_string)
...

在这里插入图片描述


接着进入CleanupTransaction函数进行清理!


接下来进入今天的重点,如下:

			if (s->chain)
			{
				StartTransaction();
				s->blockState = TBLOCK_INPROGRESS;
				s->chain = false;
				RestoreTransactionCharacteristics(&savetc);
			}

因为chain为真,这里还是再重启一个事务。不过这种类似于XactReadOnly的guc参数在StartTransaction过程中仍被赋值默认值!该参数的重新修改如下:

在这里插入图片描述

至此,rollback and chain 操作回滚了上一个事务,并开启新的事务 且XactReadOnly = true,得以保留!


同上面rollback and chain操作一样,其他几种 如下:

// src/backend/access/transam/xact.c

/*
 *	CommitTransactionCommandInternal - a function doing an iteration of work
 *		regarding handling the commit transaction command.  In the case of
 *		subtransactions more than one iterations could be required.  Returns
 *		true when no more iterations required, false otherwise.
 */
static bool
CommitTransactionCommandInternal(void)
{
	...
			/*
			 * We are completing a "COMMIT" command.  Do it and return to the
			 * idle state.
			 */
		case TBLOCK_END:
			CommitTransaction();
			s->blockState = TBLOCK_DEFAULT;
			if (s->chain)				// here
			{
				StartTransaction();
				s->blockState = TBLOCK_INPROGRESS;
				s->chain = false;
				RestoreTransactionCharacteristics(&savetc);
			}
			break;
	...
			/*
			 * Here we were in an aborted transaction block and we just got
			 * the ROLLBACK command from the user, so clean up the
			 * already-aborted transaction and return to the idle state.
			 */
		case TBLOCK_ABORT_END:
			CleanupTransaction();
			s->blockState = TBLOCK_DEFAULT;
			if (s->chain)				// here
			{
				StartTransaction();
				s->blockState = TBLOCK_INPROGRESS;
				s->chain = false;
				RestoreTransactionCharacteristics(&savetc);
			}
			break;
	...
			/*
			 * Here we were in a perfectly good transaction block but the user
			 * told us to ROLLBACK anyway.  We have to abort the transaction
			 * and then clean up.
			 */
		case TBLOCK_ABORT_PENDING:
			AbortTransaction();
			CleanupTransaction();
			s->blockState = TBLOCK_DEFAULT;
			if (s->chain)				// here
			{
				StartTransaction();
				s->blockState = TBLOCK_INPROGRESS;
				s->chain = false;
				RestoreTransactionCharacteristics(&savetc);
			}
			break;
	...
			/*
			 * The user issued a COMMIT, so we end the current subtransaction
			 * hierarchy and perform final commit. We do this by rolling up
			 * any subtransactions into their parent, which leads to O(N^2)
			 * operations with respect to resource owners - this isn't that
			 * bad until we approach a thousands of savepoints but is
			 * necessary for correctness should after triggers create new
			 * resource owners.
			 */
		case TBLOCK_SUBCOMMIT:
			do
			{
				CommitSubTransaction();
				s = CurrentTransactionState;	/* changed by pop */
			} while (s->blockState == TBLOCK_SUBCOMMIT);
			/* If we had a COMMIT command, finish off the main xact too */
			if (s->blockState == TBLOCK_END)
			{
				Assert(s->parent == NULL);
				CommitTransaction();
				s->blockState = TBLOCK_DEFAULT;
				if (s->chain)				// here
				{
					StartTransaction();
					s->blockState = TBLOCK_INPROGRESS;
					s->chain = false;
					RestoreTransactionCharacteristics(&savetc);
				}
			}
			else if (s->blockState == TBLOCK_PREPARE)
			{
				Assert(s->parent == NULL);
				PrepareTransaction();
				s->blockState = TBLOCK_DEFAULT;
			}
			else
				elog(ERROR, "CommitTransactionCommand: unexpected state %s",
					 BlockStateAsString(s->blockState));
			break;
	...
}

对应非特殊的guc参数,能否可以继承呢?如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17beta2)
Type "help" for help.

postgres=# show timezone;
      TimeZone       
---------------------
 America/Los_Angeles
(1 row)

postgres=# begin;
BEGIN
postgres=*# set timezone = 'PRC';
SET
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*# commit and chain; ## commit 提交 && 继承
COMMIT
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*# rollback and chain; ## 无东西可以回滚
ROLLBACK
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*#
[postgres@localhost:~/test/bin]$ ./psql 
psql (17beta2)
Type "help" for help.

postgres=# show timezone;
      TimeZone       
---------------------
 America/Los_Angeles
(1 row)

postgres=# begin;
BEGIN
postgres=*# desc a error;
2024-07-01 06:19:56.969 PDT [34810] ERROR:  syntax error at or near "desc" at character 1
2024-07-01 06:19:56.969 PDT [34810] STATEMENT:  desc a error;
ERROR:  syntax error at or near "desc"
LINE 1: desc a error;
        ^
postgres=!# show timezone;
2024-07-01 06:20:00.721 PDT [34810] ERROR:  current transaction is aborted, commands ignored until end of transaction block
2024-07-01 06:20:00.721 PDT [34810] STATEMENT:  show timezone;
ERROR:  current transaction is aborted, commands ignored until end of transaction block
postgres=!# 
postgres=!# commit and chain; ## commit 这里相当于先回滚 && 继承
ROLLBACK
postgres=*# show timezone;
      TimeZone       
---------------------
 America/Los_Angeles
(1 row)

postgres=*# set timezone = 'PRC';
SET
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*# commit and chain; ## commit 提交 && 继承
COMMIT
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*# rollback and chain; ## 无东西可以回滚
ROLLBACK
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*# reset timezone;
RESET
postgres=*# show timezone;
      TimeZone       
---------------------
 America/Los_Angeles
(1 row)

postgres=*# rollback and chain; ## rollback 这里相当于先回滚 && 继承
ROLLBACK
postgres=*# show timezone;
 TimeZone 
----------
 PRC
(1 row)

postgres=*#

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/762995.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

反激开关电源反馈电路相关参数选型

Vb的电压正常变化范围是:0-1V(最低0V,由于有稳压管,最高不会超过1V) Vb的电压越高,则输出占空比越大,Vb电压越低,则输出占空比越小 那么Va的正常变化范围应该是:1.4-4.…

文本生成sql模型(PipableAI/pip-sql-1.3b)

安装环境 pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 pip install transformers 代码 question "What are the email address, town and county of the customers who are of the least common gender?"sc…

IT专业入门——高考假期预习指南,我来做你的引路人

目录 认识IT知识体系 什么是计算机 按规模、速度和功能分类 按照其工作模式分类 硬件 操作系统 编程语言 对学习语言的一点建议 对于学python的一点看法 网络 数据结构与算法 数据库 Web开发 Web前端 Web后端 基础预习指南 技术路线学习一览 学习资源推荐 刷…

白话负载均衡、正反向代理(入门科普版)

什么是负载均衡?为什么需要负载均衡 从字面上理解,什么是负载,服务器承受访问量的大小是负载,但是单台服务器的访问性能是有限的,最典型的例子就是双十一、春运抢票这种,这时候就需要一种方案来解决这类问…

ARM功耗管理软件之DVFSAVS

安全之安全(security)博客目录导读 思考:功耗管理软件栈及示例?WFI&WFE?时钟&电源树?DVFS&AVS? 目录 一、ARM功耗管理软件之DVFS 二、ARM功耗管理软件之AVS 一、ARM功耗管理软件之DVFS 有一个实现特定…

SparkSQL调优

SparkSQL调优 文章目录 SparkSQL调优Explain 查看执行计划语法执行计划处理流程 资源调优内存说明spark任务提交到yarn上运行命令 CPU优化 SparkSQL语法优化基于RBO优化基于CBO优化广播join方式一:通过参数指定自动广播方式二:强行广播 SMB Join 数据倾斜…

Go线程实现模型-P

P 概述 P是G能够在M中运行关键。Go的运行时系统会适时地让P与不同的M建立或断开关联,以使P中的那些可运行的G能够及时获得,这与操作系统内核在CPU之上实时切换不同进程或线程的情况类似 改变P的数量 改变单个Go程序间拥有的P的最大数量有两种方法 调…

安卓手机的自带录屏在哪里找?5个软件帮助你快速给手机录屏

安卓手机的自带录屏在哪里找?5个软件帮助你快速给手机录屏 在安卓手机上进行屏幕录制是一项非常实用的功能,特别是对于需要录制游戏操作、制作教程或演示的用户来说。虽然部分安卓手机可能已经预装了屏幕录制功能,但有时候这些功能可能隐藏在…

技术派Spring事件监听机制及原理

Spring事件监听机制是Spring框架中的一种重要技术,允许组件之间进行松耦合通信。通过使用事件监听机制,应用程序的各个组件可以在其他组件不直接引用的情况下,相互发送和接受消息。 需求 在技术派中有这样一个需求,当发布文章或…

每日Attention学习7——Frequency-Perception Module

模块出处 [link] [code] [ACM MM 23] Frequency Perception Network for Camouflaged Object Detection 模块名称 Frequency-Perception Module (FPM) 模块作用 获取频域信息,更好识别伪装对象 模块结构 模块代码 import torch import torch.nn as nn import to…

Ubuntu(通用)—网络加固—ufw+防DNS污染+ARP绑定

1. ufw sudo ufw default deny incoming sudo ufw deny in from any to any # sudo ufw allow from any to any port 5353 protocol udp sudo ufw enable # 启动开机自启 # sudo ufw reload 更改后的操作2. 防ARP欺骗 华为云教程 arp -d删除dns记录arp -a显示arp表 ipconfi…

IMU在手语识别中的应用

近期,一款由美国和中国科研团队联合研发的新型的穿戴设备——SignRing,以其独特的IMU(惯性测量单元)技术,为聋哑人士的手语识别带来了革命性的突破。SignRing不仅极大地扩展了手语识别的词汇量,更提高了识别…

C++多态~~的两个特殊情况

目录 1.多态的概念 2.简单认识 (1)一个案例 (2)多态的两个满足条件 (3)虚函数的重写 (4)两个特殊情况 1.多态的概念 (1)多态就是多种形态; …

windows USB设备驱动开发-双角色驱动

在USB的通讯协议中,规定发起连接的一方为主机(Host),接受连接的一方为设备,这可以用U盘插入电脑举个例子,当U盘插入电脑后,电脑这边主动发起查询和枚举,U盘被动响应查询和数据存取。 USB 双角色驱动程序堆…

为Ubuntu-24.04-live-server-amd64磁盘扩容

系列文章目录 Ubuntu-24.04-live-server-amd64安装界面中文版 文章目录 系列文章目录前言一、检查系统本身情况1.用 lsblk 命令查看自己系统磁盘是什么状态2.用 df -h 命令查看文件系统的磁盘空间使用情况3.解决 Ubuntu-24.04 磁盘空间只能用一半的问题3-1扩展逻辑卷&#xff…

二叉树层序遍历

题目描述 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 假设有这样一棵二叉树,那么它经过层序遍历的结果就应该是: [[3],[9,20],[15,7]]解法 我们可以用广度…

css美化滚动条样式

效果展示 实现 滚动条宽,高度 /* 整体滚动条 */ ::-webkit-scrollbar {width: 10px; }/* 滚动条轨道 */ ::-webkit-scrollbar-track {background-color: #ffffff;border-radius: 6px; }/* 滚动条滑块 */ ::-webkit-scrollbar-thumb {background-color: #888;borde…

IDEA安装使用、JDBC

day53续 IDEA安装 浏览器搜索,在idea官网直接下载需要的版本安装包,安装流程基本无脑 对于专业版要激活,可找相关资源也可购买;社区版不需要 配置环境变量 JDBC JDBC:java database connectivity SUN公司提供的一套操作数据库的…

计算机毕业设计Python深度学习美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

Python美食推荐系统开题报告 一、项目背景与意义 随着互联网和移动技术的飞速发展,人们的生活方式发生了巨大变化,尤其是餐饮行业。在线美食平台如雨后春笋般涌现,为用户提供了丰富的美食选择。然而,如何在海量的餐饮信息中快速…

【Excel、RStudio计算T检测的具体操作步骤】

目录 一、基础知识1.1 显著性检验1.2 等方差T检验、异方差T检验1.3 单尾p、双尾p1.3.1 检验目的不同1.3.2 用法不同1.3.3 如何选择 二、Excel2.1 统计分析工具2.1.1 添加统计分析工具2.1.2 数据分析 2.2 公式 -> 插入函数 -> T.TEST 三、RStudio 一、基础知识 参考: 1.…