gpt4 book ai didi

c++ - postgresql 在数据库服务器中消耗更多内存以进行长时间运行的连接

转载 作者:行者123 更新时间:2023-11-29 12:53:22 36 4
gpt4 key购买 nike

我们有一个 C++ 服务器应用程序,它使用 libpq 库连接到 postgresql 数据库。应用程序创建 100 秒的数据库连接,连接的大部分生命周期都是应用程序范围。

最初应用程序运行良好,但在一段时间后,postgres 服务器为长时间运行的连接消耗了更多内存。通过编写下面的示例程序,我了解到使用 PQsendPreparePQsendQueryPrepared 创建准备好的语句会导致数据库服务器中的内存消耗问题。

我们如何解决这个服务器内存问题?是否有任何 libpq 函数可以释放服务器中的内存?

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <libpq-fe.h>

int main(int argc, char *argv[]) {

const int LEN = 10;
const char *paramValues[1];

int paramFormats[1];
int rowId = 7369;
Oid paramTypes[1];
char str[LEN];
snprintf(str, LEN, "%d", rowId);
paramValues[0] = str;
paramTypes[0]=20;
paramFormats[0]=0;
long int c=1;

PGresult* result;
//PGconn *conn = PQconnectdb("user=scott dbname=dame");
PGconn *conn = PQsetdbLogin ("", "", NULL, NULL, "dame", "scott", "tiger") ;

if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr, "Connection to database failed: %s\n",
PQerrorMessage(conn));
do_exit(conn);
}
char *stm = "SELECT coalesce(ename,'test') from emp where empno=$1";
for(;;)
{
std::stringstream strStream ;
strStream << c++ ;
std::string strStatementName = "s_" + strStream.str() ;
if(PQsendPrepare(conn,strStatementName.c_str(), stm,1,paramTypes) )
{
result = PQgetResult(conn);
if (PQresultStatus(result) != PGRES_COMMAND_OK)
{
PQclear(result) ;
result = NULL ;
do
{
result = PQgetResult(conn);
if(result != NULL)
{
PQclear (result) ;
}
} while (result != NULL) ;
std::cout<<"error prepare"<<PQerrorMessage (conn)<<std::endl;
break;
}
PQclear(result) ;
result = NULL ;
do
{
result = PQgetResult(conn);
if(result != NULL)
{
PQclear (result) ;
}
} while (result != NULL) ;
}
else
{
std::cout<<"error:"<<PQerrorMessage (conn)<<std::endl;
break;
}

if(!PQsendQueryPrepared(conn,
strStatementName.c_str(),1,(const char* const *)paramValues,paramFormats,paramFormats,0))
{
std::cout<<"error:prepared "<<PQerrorMessage (conn)<<std::endl;
}
if (!PQsetSingleRowMode(conn))
{
std::cout<<"error singrow mode "<<PQerrorMessage (conn)<<std::endl;
}
result = PQgetResult(conn);
if (result != NULL)
{
if((PGRES_FATAL_ERROR == PQresultStatus(result)) || (PGRES_BAD_RESPONSE == PQresultStatus(result)))
{
PQclear(result);
result = NULL ;
do
{
result = PQgetResult(conn);
if(result != NULL)
{
PQclear (result) ;
}
} while (result != NULL) ;
break;
}

if (PQresultStatus(result) == PGRES_SINGLE_TUPLE)
{
std::ofstream myfile;
myfile.open ("native.txt",std::ofstream::out | std::ofstream::app);
myfile << PQgetvalue(result, 0, 0)<<"\n";
myfile.close();
PQclear(result);
result = NULL ;
do
{
result = PQgetResult(conn) ;
if(result != NULL)
{
PQclear (result) ;
}
}
while(result != NULL) ;
sleep(10);
}
else if(PQresultStatus(result) == PGRES_TUPLES_OK || PQresultStatus(result) == PGRES_COMMAND_OK)
{
PQclear(result);
result = NULL ;
do
{
result = PQgetResult(conn) ;
if(result != NULL)
{
PQclear (result) ;
}
}
while(result != NULL) ;
}
}

}

PQfinish(conn);
return 0;

}

最佳答案

Initially application was running fine, but over a period of time postgres server consuming more memory for long running connections. By writing a below sample program I come to know creating prepared statements using PQsendPrepare and PQsendQueryPrepared is causing the memory consumption issue in database server.

嗯,这似乎不足为奇。您在外循环的每次迭代中生成一个新的准备语句名称,然后创建并执行该名称的准备语句。只要连接处于打开状态,所有由此产生的、名称不同的准备好的语句确实会保留在服务器的内存中。这是故意的。

How we can fix this server memory issue?

我将其描述为程序逻辑问题,而不是服务器内存问题,至少就测试程序而言是这样。您获取资源(准备好的语句),然后在您不再使用它们时允许它们闲逛。语句本身并没有泄漏,因为您可以重新创建算法生成的语句名称,但问题类似于资源泄漏。在您的程序中,而不是在 Postgres 中。

如果你想使用一次性准备好的语句,那么给它们一个空字符串,"",作为它们的名字。 Postgres 称这些为“未命名”语句。您准备的每个未命名语句都将替换属于同一连接的任何先前语句。

但即便如此,这也是一个 hack。首先,准备好的语句最重要的特性是它们可以重用。你的测试程序准备的每条语句都是相同的,所以你不仅在浪费内存,也在浪费 CPU 周期。你应该只准备一次——通过PQsendPrepare(),或者可能只是PQprepare()——当它成功准备好后,执行它的次数不限想要使用 PQsendQueryPrepared()PQqueryPrepared(),每次都传递相同的语句名称(但可能有不同的参数)。

is there any libpq function to free the memory in server?

The documentation for the synchronous versions of the query functions说:

Prepared statements for use with PQexecPrepared can also be created by executing SQL PREPARE statements. Also, although there is no libpq function for deleting a prepared statement, the SQL DEALLOCATE statement can be used for that purpose.

据我所知,在 Postgres 中只有一种预准备语句,同步函数和异步函数都使用类似的语句。所以不,libpq 没有提供专门用于删除与连接关联的准备好的语句的功能,但您可以在 SQL 中编写语句来完成这项工作。当然,创建一个新的、唯一命名的预处理语句来执行这样的语句是没有意义的。

大多数程序不需要这么多不同的准备语句来产生您报告的那种问题。

关于c++ - postgresql 在数据库服务器中消耗更多内存以进行长时间运行的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48980858/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com