PostgreSQL查询启动过程
本文PG代码版本为:REL_14_STABLE(PG 14稳定分支)。
psql连接创建服务进程
客户端psql连接PG server成功后,PostMaster(守护进程)会fork出来一个服务进程(Backend),如下所示:
[yz@localhost ~]$ ps -ef | grep postgres yz 14560 1 0 11:25 ? 00:00:00 /home/yz/postgresql/pg_bin/bin/postgres -D /home/yz/postgresql/pg_data yz 14627 14560 0 11:25 ? 00:00:00 postgres: checkpointer yz 14628 14560 0 11:25 ? 00:00:00 postgres: background writer yz 14629 14560 0 11:25 ? 00:00:00 postgres: walwriter yz 14630 14560 0 11:25 ? 00:00:00 postgres: autovacuum launcher yz 14631 14560 0 11:25 ? 00:00:00 postgres: stats collector yz 14632 14560 0 11:25 ? 00:00:00 postgres: logical replication launcher yz 14637 14431 0 11:25 pts/0 00:00:00 psql -p 7404 postgres yz 14638 14560 0 11:25 ? 00:00:00 postgres: yz postgres [local] idle
14638是为14637服务的进程,其父进程为14560。
监听端口
之后,服务进程进入无限循环,监听连接端口上的消息,即:
- snippet.c
void PostgresMain(int argc, char *argv[], const char *dbname, const char *username) { /* * Non-error queries loop here. */ for (;;) { // read a command firstchar = ReadCommand(&input_message); switch (firstchar) { case 'Q': /* simple query */ { exec_simple_query(query_string); } } }
psql发送查询
假设psql执行一条select命令,则psql通过libpq将消息发送给后端服务进程:
(gdb) bt #0 0x00007f4ef75b2400 in PQsendQuery () from /home/yz/postgresql/pg_bin/lib/libpq.so.5 #1 0x00007f4ef75b3260 in PQexec () from /home/yz/postgresql/pg_bin/lib/libpq.so.5 #2 0x000000000040d2af in SendQuery () #3 0x000000000041ebb4 in MainLoop () #4 0x0000000000406347 in main ()
PQsendQuery实际调用PQsendQueryInternal,可以看到以下代码:
- snippet.c
if (pqPutMsgStart('Q', conn) < 0 || pqPuts(query, conn) < 0 || pqPutMsgEnd(conn) < 0) { /* error message should be set up already */ pqRecycleCmdQueueEntry(conn, entry); return 0; }
'Q'指令就是在这里生成的。
执行
服务进程收到查询请求,执行主要由:
exec_simple_query
负责执行,包括语法解析、生成执行计划、优化、算子执行等。
执行过程中,如果有并行,则需要发信号(signal)给PostMaster,PostMaster会fork worker进程。
打赏作者以资鼓励: