我正在开发一个C++应用程序,并使用libpq库将其插入到本地Postgres数据库中.我遇到了一个问题,如果我try 使用预准备语句查询数据库,如果参数太长,查询似乎会挂起(具体地说,这在恰好393167个字符[参数的组合字符计数]处开始发生).我是PSQL的新手,所以我会尽量具体一点.如果需要更多信息,请告诉我.

以下是我到目前为止采取的一些笔记/步骤:

  • 我在postgresql.conf中将LOG_STATENTS更改为‘ALL’.它看起来 查询正在到达数据库,因为它正在记录 查询.
  • 如果参数的长度再少一个(393166),则运行时不会出现任何问题.
  • 如果我通过不带参数/预准备语句的libpq运行类似的INSERT查询,并直接执行,那么它对于更大的查询(数百万个字符)来说运行得很好.例如:insert into...values('test12', 'aaa....');
  • 角色是什么似乎并不重要.
  • 查询性能在接近此限制时不会降低.它非常快,但当它达到这个字符限制时,似乎会撞到墙上.
  • 我已经将work_mem增加到允许的最大"2097151kB",但这并没有帮助. 我猜我的Postgres设置有一些问题,但我在弄清楚它可以或在哪里查看时遇到了很多问题.

下面是一个查询示例:(如日志(log)中所示)

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++文件,该文件向PostgreSQL15.2写入大文本,并且能够使用libpq5毫无问题地写入该文件.

System

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

DB

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]

Table

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++ code

#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;
}

Compile and run

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还是pg15.2.然后,我们必须做淘汰测试.

  • 保留libpq并针对PG 12运行代码,看看是否运行得更好,或者
  • 保留第15.2页,并使用与libpq不同的库.

References

Postgresql相关问答推荐

PostgreSQL中btree_gist索引涉及integer和tstzrange属性查询计划的问题

将XML解析从T-SQL迁移到Postgres时出现问题

在PostgreSQL中,`MY_VARIABLE IN(<;Long_ARRAY_of_Items>;)`何时是FAST?

如何获得一起满足数量要求的物品? (WHILE 循环还是 CTE?)postgresql

尽管违反了部分索引约束,Postgres 插入仍在发生

错误:用户需要系统密码:postgres

未更改表上的 Postgres 环绕预防

使用正则表达式计算 SQL 查询中 WHERE 过滤器的数量

EF Core添加迁移目标postgreeSQL返回无法加载类型'Microsoft.EntityFrameworkCore.Storage.IRelationalValueBufferFactoryFactory

转换数组类型

是否可以在 PostgreSQL 中部分刷新materialized视图?

如何确定 NULL 是否包含在 Postgres 的数组中?

没有查询要创建的in ... error

如何为查询执行设置语句超时

如何在数据库表中查找重复条目?

Rails:PG :: InsufficientPrivilege:错误:permission denied for relation schema_migrations

获取 psycopg2 count(*) 结果数

SQL 基本类型:integer vs int?

Windows 上的 GeoDjango:Could not find the GDAL library" / "OSError: [WinError 126] The specified module could not be found

如何在不丢失openproject数据的情况下将postgresql数据库从10升级到12