performance - 如何在 PostgreSQL 中快速插入 BLOB?

标签 performance postgresql

您对配置 PostgreSQL 以快速编写 BLOB 有何建议?

我们正在使用 PostgreSQL 以高速率插入 BLOB。

  1. 我们大约每秒调用 lo_write() 220 次。
  2. 我们每次 lo_write() 写入大约 30KB 的二进制数据。
  3. 这相当于大约 6 MB/s。

我们的计算机是 RAID-5,因此写入速度在 200 MB/s 左右。

我们已经将 postgresql.conf 调整为具有以下内容:

  1. 我们更改了 shared_buffers = 1GB
  2. 我们关闭了 fsync
  3. logging_collector = off(几乎所有与日志相关的东西都关闭)

我们已经确保,如果我们不将 BLOB 存储为我们的 INSERT 查询的一部分,那么 PgSql 会保持良好状态。只有当我们将 BLOB 存储为查询的一部分时,它才会变慢。

编辑:我使用的是 Windows XP/Server。我将 Pgsql 8.3 与 PostGIS 1.3.6 一起使用。我需要将 BLOB 存储在数据库中的原因是因为我的应用程序需要我实时搜索这些 BLOB。

背景:我们的应用是高性能实时信号处理,我们将信号作为 BLOB 存储到数据库中。

编辑:这是我们用来执行基准测试的 C++ 代码。显然,我们的 RAID 配置速度大约为 16 MB/s。

#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#include <sstream>
#include <iostream>
#include <tbb/tick_count.h>

void test()
{
  std::stringstream stst;
  stst << "user=postgres password=1234 dbname=test_db";
  PGconn* conn = PQconnectdb(stst.str().c_str());
  if (PQstatus(conn) != CONNECTION_OK)
  {
    throw std::exception("failed to connect To DB engine: ");
  }

  const int dataSize = 18512;
  char* data = (char*) malloc( dataSize );


  const int count = 10000;

  tbb::tick_count t0 = tbb::tick_count::now();
  for( int idx = 0; idx < count; idx++ )
  {
    // Insert acoustic binary into large object table "pg_largeobject" 
    Oid objectId;
    int lobj_fd;
    PGresult *res;

    res = PQexec(conn, "begin");
    PQclear(res);

    objectId = lo_creat(conn, INV_READ|INV_WRITE);
    if (objectId == 0)
    {
      throw std::exception("AddAcousticTable: Cannot create large object\n");
    }

    lobj_fd = lo_open(conn, objectId, INV_WRITE);

    const unsigned int writeBytes = lo_write(conn, lobj_fd, data, dataSize );
    if (writeBytes != dataSize )
    {
      std::stringstream msg;
      msg << "PsSasDataDB::AddToAcousticTable(): Incorrect number of bytes written for large object ";
      msg << writeBytes;
      throw std::exception(msg.str().c_str());
    }

    lo_close(conn, lobj_fd);

    res = PQexec(conn, "end");
    PQclear(res);
  }
  tbb::tick_count t1 = tbb::tick_count::now();

  std::cout << "Performance: " << (double(count*dataSize)/(t1-t0).seconds())/(1024.0*1024.0) << " MB/seconds";

  free( data );
}
int main()
{
  try
  {
    test();
  }
  catch( std::exception e )
  {
    std::cerr << e.what();
  }

  return 0;
}

最佳答案

RAID5:

它非常适合读取、写入大量大数据和降低成本。 对于小的随机写入来说很糟糕。

由于您可能不使用您的数据库来仅存储大 blob,您还进行一些数据库写入/更新/插入,RAID5 将成为真正的 PITA。

  • 您在表中插入或更新一行。 -> 表格中的一页需要写入 -> 对于每个索引,至少需要更新一个索引页 -> 在提交时,需要写入日志、刷新到磁盘并同步。

这些小的 1 页 (8kB) 写入中的每一个都小于您的 RAID5 strip 大小,因此 RAID Controller 将需要寻找几个(或所有)您的 RAID 磁盘,读取多个 strip ,然后重新写入更新的 strip 和平价。对于同步,您必须等待所有磁盘同步,在此期间它们不为任何其他请求提供服务……一些 RAID Controller 在执行此速度方面也特别糟糕,这取决于您的硬件。

-> 对于高随机写入吞吐量,最好对数据使用 RAID 1(或 10 或 01),并在 2 个单独的磁盘上为日志使用额外的 RAID1 卷。

因此,如果您的 RAID5 中有 3 个磁盘,请移除一个,将数据放在磁盘上并在另一个磁盘上登录,然后进行基准测试。如果好的话,再多加一 block 盘,做2个RAID1卷(日志,数据)。

如果您的负载是重读而不是重写,对于相同的预算(磁盘数量),最好将日志放在与数据相同的卷上,并且全部采用 RAID10。


The reason why I needed to store BLOB in the DB is because my application requires me to search for these BLOBs in real-time.

如果你想使用数据库擅长的东西(比如事务、安全性,或者把所有东西都放在一台服务器上,从任何地方都可用,连贯的备份,没有麻烦,等等),你可以把 BLOB 放在数据库中。

如果您想进行搜索,您不是使用 BLOB 进行搜索,而是使用简单的数据库表和 SQL 查询来获取对所需 BLOB 的引用。然后,您将获得 BLOB,但您也可以轻松地获得一个文件系统文件。因此,在您的应用程序中,您也可以改用文件系统文件,这样会快很多。

关于performance - 如何在 PostgreSQL 中快速插入 BLOB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1174848/

相关文章:

php - 有效限制 PHP 中每分钟的点击次数(阻止网页抓取或复制机器人)

database - 备份/恢复 dockerized PostgreSQL 数据库

postgresql - 如何将字符串转换为所需时区的时间戳

sql - 更新规则和 PostgreSQL 中的 ‘column reference is ambiguous’ 错误

javascript - 用 jquery 分配一个 javascript 变量只需要执行一次?

sql - 我如何优化这个更新每一行的 PostgreSQL 查询?

javascript - 如何通过多个相同的属性过滤对象数组

performance - MATLAB for 循环索引的最佳实践

java - JPA @GenerateValue 与 PostgreSQL 生成的序列值中的差距

linux - 使用 MS Sync Framework 将 SQL Server 2012 同步到 Postgres 9