postgresql - 当参数大小超过 393166 个字符时,PSQL 准备好的语句查询会挂起

标签 postgresql windows libpq

我正在开发一个 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/

相关文章:

postgresql - 为什么 `libpq` 使用轮询而不是通知来获取数据?

c - libpq 以二进制形式发送整数

连接表和多个值的 SQL 查询

postgresql - 如何在 Postgres 9.6 中的 uuid 上添加 PostgreSQL GIN 索引

c - 类似于 pthread_cancel 的 Windows API?

java - gcloud Preview 应用程序在 Windows 上运行 "bad port Access Denied"错误

postgresql - libpq: lo_open() 返回 0

Django + Psycopg2 : InterfaceError: only protocol 3 supported

PHP 从 postgresql 数据库构建特定的 JSON 字符串

windows - 在 Windows PowerShell 中运行 VS 2017 构建工具