【问题标题】:libpq very slow for large (20 million record) database对于大型(2000 万条记录)数据库,libpq 非常慢
【发布时间】:2012-07-29 16:45:15
【问题描述】:

我是 SQL/RDBMS 的新手。

我有一个应用程序,它使用 libpq 库在 PostgreSQL 服务器中添加 10 列的行。现在,我的服务器与我的 Visual C++ 应用程序在同一台机器上运行。

我添加了大约 15-20 百万条记录。使用 select count(*) from <tableName>; 获取总数的简单查询需要 4-5 分钟。

我已经用我输入数据的时间(时间码)索引了我的表。大多数时候,我需要添加不同的 WHERE / AND 子句。

有什么方法可以让事情变得快速吗?我需要让它尽可能快,因为一旦服务器移动到网络,事情就会变得更慢。

谢谢

【问题讨论】:

  • 你使用的是哪个版本的 Postgres?
  • @garfield 每次您post a question,都会有人询问您的 PostgreSQL 版本。这不是暗示你应该在你提问时把它放进去吗?
  • 你的硬件一定有问题。 count(*) 的 5 分钟太长了。
  • @a_horse_with_no_name 硬件有问题,并发查询运行,或者大量表膨胀,是的。

标签: sql postgresql visual-c++


【解决方案1】:

我认为网络延迟不会成为影响查询所需时间的重要因素。所有处理都在 PostgreSQL 服务器上完成。

PostgreSQL MVCC 设计意味着必须遍历表中的每一行——不仅仅是索引——来计算计数(*),这是一项昂贵的操作。在您的情况下,涉及很多行。

http://wiki.postgresql.org/wiki/Slow_Counting 有一个很好的关于这个主题的 wiki 页面,上面有建议。

来自这个链接的两个建议,一个是使用索引列:

select count(index-col) from ...;

...虽然这只在某些情况下有效。

如果您有多个索引,请使用以下方法查看哪个索引成本最低:

EXPLAIN ANALYZE select count(index-col) from ...;

如果你可以接受一个近似值,另一种方法是使用 Postgres 特定函数来获取近似值,例如:

select reltuples from pg_class where relname='mytable';

这个近似值的好坏取决于 autovacuum 设置运行的频率以及许多其他因素;见 cmets。

【讨论】:

  • 但这可以帮助我获取总表的计数。在表条目中,我有一列按顺序增加长整数。总计数将等于最后一行该列的值。可以进行这么多的优化。但是,当在我的查询中添加“where”和“and”时,情况就会变得更糟。此外,如果我在“count(...)”中提供列名,它会有什么不同,因为 postgre 必须再次遍历所有列才能得到计数。
  • 如果您的列被索引,PG 将只需要计算索引条目 - 而不是完整的表行。此外,放置 where 子句将限制行并且应该加快速度。试试看。并且你可以尝试不同的索引 + EXPLAIN ANALYZE 看看它们有什么效果。
  • @Garfield 当你说“连续递增的长整数”时,你的意思是 SEQUENCE 还是 SERIAL / BIGSERIAL ?因为它们可能有缝隙或孔洞。即使您从未删除过一行,最大 ID 也不一定等于行数。每次您执行INSERT 然后回滚事务时,您都会丢弃生成的 ID,留下一个漏洞。漏洞也可能以其他方式发生。 max(id)serialcount(id)相同。
  • @pd420 实际上并非如此。即使进行索引扫描,PostgreSQL 仍然必须命中表堆以检查可见性数据,正如您链接到的慢计数 wiki 文章所解释的那样。这在 9.2 中新的“仅索引扫描”功能得到了很大改善,但对于以前的版本,仍然必须检查可见性。 (IIRC) 8.4 及更高版本中的可见性地图如果是最新的,可以允许采取一些快捷方式,但有限制。
  • @CraigRinger:我自己并不完全确定,希望能从你那里得到更多信息。 :) 所以我又研究了一些手册,它相当复杂。 reltuples 由各种操作设置。除了ANALYZE,还有VACUUMVACUUM FULLCLUSERCREATE INDEX .. 和其他人 - Postgres 会利用一切机会。对于大表,ANALYZE 仅扫描随机页面样本并保存估计值。所有列之间最高的statistics_target 用于确定随机样本中的页数。这样,它会对reltuples 的准确性产生(很小的)影响。
【解决方案2】:

考虑pg_relation_size('tablename') 并将其除以花费的秒数

select count(*) from tablename

这将在对该表进行全面扫描时提供磁盘的吞吐量。如果它太低,您首先要专注于改进它。 拥有良好的 I/O 子系统和性能良好的操作系统磁盘缓存对于数据库至关重要。

默认的 postgres 配置是为了不消耗太多资源来与其他应用程序配合使用。根据您的硬件和机器的整体利用率,您可能需要向上调整几个性能参数,例如 shared_bufferseffective_cache_sizework_mem .请参阅特定版本的文档和 wiki 的 performance optimization 页面。

还要注意select count(*) 样式查询的速度与libpq 或网络无关,因为只检索到一个结果行。它完全发生在服务器端。

【讨论】:

  • 它也可能因表膨胀而减慢,因此请注意这一点。如果您执行大量 updates 和 deletes,请确保 autovacuum 经常运行。
【解决方案3】:

您没有说明您的数据是什么,但通常处理具有大量数据的表的原因是对表进行分区。 http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

这不会加快您的 select count(*) from <tableName>; 查询,甚至可能会减慢它,但如果您通常只对表中的部分数据感兴趣,这可能会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2018-12-31
    • 2017-06-18
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多