我正在开发一个 C++ 应用程序,并使用 libpq 库插入本地 postgres 数据库。我遇到了一个问题,如果我尝试使用准备好的语句查询数据库,如果参数太长,查询就会挂起(具体来说,这种情况开始发生在正好 393167 个字符 [参数的组合字符数] 处)。我是 psql 的新手,所以我会尽可能具体。如果需要更多信息,请告诉我。
以下是我迄今为止采取的一些注释/步骤:
- 我在 postgresql.conf 中将 log_statments 更改为“all”。它出现 查询正在到达数据库,因为它正在记录 查询。
- 如果参数的长度再少一(393166),运行就不会出现问题。
- 如果我通过 libpq 运行类似的 INSERT 查询(不带参数/准备好的语句)并直接执行,则它对于更大的查询(数百万个字符)运行良好。例如:
插入...values('test12', 'aaa....');
- 角色是什么似乎并不重要。
- 当查询性能接近此限制时,查询性能不会降低。它速度非常快,但当达到此字符限制时似乎会碰壁。
- 我已将 work_mem 增加到允许的最大值“2097151kB”,但这并没有帮助。 我猜测我的 postgres 设置存在一些问题,但我很难弄清楚它可以做什么或在哪里查找。
这是一个示例查询:(如日志中所示)
2023-05-04 16:25:04.657 CDT [36340] LOG: execute 2: INSERT INTO public.knowledge
(userid, knowledge) VALUES ($1, $2)
2023-05-04 16:25:04.657 CDT [36340] DETAIL: parameters: $1 = 'test12', $2 =
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....'
最佳答案
我尝试在 Linux 上复制该问题,但失败了。我目前没有可用的 Windows 系统。我创建了一个测试 C++ 文件,该文件将大文本写入 PostgreSQL 15.2,并且能够使用 libpq5 毫无问题地写入它。
系统
uname -a
Linux 75db15f94bd2 5.15.49-linuxkit #1 SMP Tue Sep 13 07:51:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"
PRETTY_NAME="Ubuntu 22.04.2 LTS
数据库
psql (15.2 (Ubuntu 15.2-1.pgdg22.04+1))
g++
g++ --version
g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
libpq
apt list --installed | grep libpq
libpq-dev/jammy-pgdg,now 15.2-1.pgdg22.04+1 amd64 [installed]
libpq5/jammy-pgdg,now 15.2-1.pgdg22.04+1 amd64 [installed]
表格
test=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+----------
public | knowledge | table | postgres
(1 row)
test=# \d knowledge
Table "public.knowledge"
Column | Type | Collation | Nullable | Default
-----------+------------------------+-----------+----------+---------
userid | character varying(255) | | |
knowledge | text | | |
C++代码
#include <stdio.h>
#include <postgresql/libpq-fe.h>
#include <string>
#include <iostream>
int main()
{
PGconn *conn;
PGresult *res;
int rec_count;
int row;
int col;
conn = PQconnectdb("dbname=test host=localhost user=postgres password=test");
if (PQstatus(conn) == CONNECTION_BAD)
{
puts("We were unable to connect to the database");
exit(0);
}
res = PQexec(conn, "select userid, knowledge from knowledge");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
puts("We did not get any data!");
exit(0);
}
rec_count = PQntuples(res);
printf("We received %d records.\n", rec_count);
puts("==========================");
PQclear(res);
const char command[] = "insert into knowledge values($1, $2);";
char cid[] = "10";
char name[] = "aaaaaaaaaa bbbbbb...many, many characters";
int nParams = 2;
const char *const paramValues[] = {cid, name};
const int paramLengths[] = {sizeof(cid), sizeof(name)};
const int paramFormats[] = {0, 0};
int resultFormat = 0;
res = PQexecParams(conn, command, nParams, NULL, paramValues, paramLengths, paramFormats,resultFormat);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
puts("Data NOT entered");
std::cout << "PQexecParams failed: " << PQresultErrorMessage(res) << std::endl;
exit(0);
}
PQclear(res);
PQfinish(conn);
return 0;
}
编译并运行
g++ test.cpp -lpq
./a.out
We received 5 records.
==========================
打印输出后,它还会进行插入。
现在让我们看看数据库。
test=# select userid, length(knowledge) from knowledge;
userid | length
--------+--------
10 | 11
10 | 393165
10 | 393166
10 | 393167
10 | 393168
10 | 393173
我能够通过参数化插入大文本。
欢迎您获取我的代码并向其提供您的数据,看看问题是否仍然存在。
如果您在 Windows 上没有发现此代码有问题,那么 libpq 就可以了。
如果您看到这个问题,那么我很好奇它是 libpq 还是 PG 15.2。然后,我们就要做淘汰测试。
- 保留 libpq 并针对 PG 12 运行代码,看看是否效果更好,或者
- 保留 PG 15.2 并使用与 libpq 不同的库。
引用文献
关于postgresql - 当参数大小超过 393166 个字符时,PSQL 准备好的语句查询会挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76177586/