优化PostgreSQL以进行快速测试

时间:2012-02-23 04:59:33

标签: sql database performance postgresql database-tuning

我正在从SQLite切换到PostgreSQL,用于典型的Rails应用程序。

问题是PG的运行规格变慢了 在SQLite上花了大约34秒,在PG上它是~76秒,慢了2倍

所以现在我想应用一些技术来使规范的性能与SQLite 相同而不需要修改代码(理想情况下只需设置连接选项,这可能是不可能的)。< / p>

我头脑中的一些显而易见的事情是:

  • RAM磁盘(在OSX上使用RSpec进行良好设置会很好看)
  • 未记录的表(它可以应用于整个数据库,所以我没有更改所有脚本吗?)

你可能已经明白我不关心可靠性和其他方面(DB在这里只是一次性的东西)。
我需要从PG中获得最大收益并使其尽可能快

最佳答案理想情况下会描述技巧来做这些,设置和这些技巧的弊端。

更新: fsync = off + full_page_writes = off仅将时间减少到约65秒(〜-16秒)。良好的开端,但远不是34的目标。

更新2 tried to use RAM disk,但性能提升在误差范围内。所以似乎不值得。

更新3:* 我找到了最大的瓶颈,现在我的规格和SQLite一样快。

问题是执行截断的数据库清理。显然SQLite在那里太快了。

要“修复”它,我会在每次测试前打开事务,并在结束时将其回滚。

〜700次测试的一些数字。

  • 截断:SQLite - 34s,PG - 76s。
  • 交易:SQLite - 17s,PG - 18s。

SQLite的速度提高了2倍。 PG的速度提高4倍。

2 个答案:

答案 0 :(得分:264)

首先,始终使用最新版本的PostgreSQL。性能改进总是随之而来,所以如果您正在调整旧版本,那么您可能会浪费时间。例如,PostgreSQL 9.2 significantly improves the speed of TRUNCATE当然会添加仅索引扫描。甚至应该遵循轻微的释放;请参阅version policy

唐&#39; TS

Do NOT put a tablespace on a RAMdisk or other non-durable storage

如果丢失了表空间,整个数据库可能会损坏,并且在没有重要工作的情况下难以使用。与仅使用UNLOGGED表并且具有大量RAM用于缓存相比,这没有什么优势。

如果你真的想要一个基于ramdisk的系统,initdb通过initdb ramdisk上的新PostgreSQL实例在ramdisk上创建一个全新的集群,那么你就拥有了一个完全一次性的PostgreSQL实例。

PostgreSQL服务器配置

测试时,您可以将服务器配置为non-durable but faster operation

这是PostgreSQL中fsync=off设置唯一可接受的用途之一。这个设置几乎告诉PostgreSQL不要打扰有序写入或任何其他令人讨厌的数据完整性保护和崩溃安全的东西,如果你失去电源或操作系统崩溃,它允许完全丢弃你的数据。

毋庸置疑,除非您将Pg用作可以从其他地方重新生成的数据的临时数据库,否则不应在生产中启用fsync=off。当且仅当您关闭fsync时,也可以关闭full_page_writes,因为它不再有任何好处。请注意fsync=offfull_page_writes适用于群集级别,因此它们会影响PostgreSQL实例中的所有数据库。

对于生产用途,您可以使用synchronous_commit=off并设置commit_delay,因为您将获得许多与fsync=off相同的好处,而不会产生巨大的数据损坏风险。如果你启用异步提交,你确实有一个丢失最近数据的小窗口 - 但是就是这样。

如果您可以选择略微更改DDL,您还可以使用Pg 9.1+中的UNLOGGED表来完全避免WAL日志记录并获得真正的速度提升,但是如果服务器将删除表的代价崩溃。没有配置选项可以使所有表都未记录,必须在CREATE TABLE期间设置。除了适合测试之外,如果您在数据库中放置了生成或不重要的数据表,除非包含您需要安全的内容,否则这样做很方便。

检查您的日志,看看您是否收到有关太多检查点的警告。如果是,您应该增加checkpoint_segments。您可能还想调整checkpoint_completion_target以平滑写出。

调整shared_buffers以适合您的工作量。这取决于操作系统,取决于您的机器发生了什么,需要一些试验和错误。默认值非常保守。如果在PostgreSQL 9.2及更低版本上增加shared_buffers,则可能需要增加操作系统的最大共享内存限制; 9.3及以上改变了他们使用共享内存来避免这种情况的方式。

如果您只使用了几个可以完成大量工作的连接,请增加work_mem以便为其提供更多内存来进行排序等等。请注意work_mem太高work_mem设置可能会导致内存不足问题,因为它的每个连接不是每个连接,因此一个查询可以有许多嵌套排序。如果您可以在EXPLAIN中看到排序到磁盘或使用log_temp_files setting(推荐)进行记录,那么只有真的必须增加fsync=off,但值可能更高让Pg选择更聪明的计划。

正如另一张海报所说,如果可能的话,将xlog和主表/索引放在单独的HDD上是明智的。单独的分区是没有意义的,你真的想要单独的驱动器。如果您使用UNLOGGED运行,那么这种分离的好处就会少得多,如果您使用random_page_cost表,则几乎没有。

最后,调整您的查询。确保您的seq_page_costeffective_cache_size反映了系统的效果,确保EXPLAIN (BUFFERS, ANALYZE)正确无误等。使用auto_explain检查各个查询计划,然后转UNLOGGED模块用于报告所有慢速查询。通过创建适当的索引或调整成本参数,您通常可以显着提高查询性能。

AFAIK无法将整个数据库或群集设置为dirty_*。能够做到这一点很有意思。考虑询问PostgreSQL邮件列表。

主机操作系统调整

您也可以在操作系统级别进行一些调整。您可能想要做的主要事情是说服操作系统不要积极地刷写磁盘写入,因为您真的不关心何时/如果他们将磁盘写入磁盘。

在Linux中,您可以使用dirty_writeback_centisecs vm.zone_reclaim_mode shared_buffers设置来控制此设置,例如INSERT INTO ... SELECT ...

调整写回设置太松弛的唯一问题是,某些其他程序的刷新可能会导致所有PostgreSQL的累积缓冲区也被刷新,导致所有阻塞写入时出现大的停顿。您可以通过在不同的文件系统上运行PostgreSQL来缓解这种情况,但有些刷新可能是设备级或整个主机级而不是文件系统级,因此您无法依赖它。

这种调整确实需要使用这些设置来查看哪种方法最适合您的工作负载。

在较新的内核上,您可能希望确保将DELETE FROM blah;设置为零,因为它可能会导致NUMA系统(目前大多数系统)出现严重的性能问题,因为它与PostgreSQL管理的方式有关{{1} }。

查询和工作负载调整

这些是需要更改代码的东西;他们可能不适合你。有些是你可以应用的东西。

如果您没有将工作批量处理到更大的交易中,请启动。许多小额交易都很昂贵,因此只要有可能并且切实可行,您就应该批量处理。如果您使用异步提交,则不太重要,但仍然强烈推荐。

尽可能使用临时表。它们不会产生WAL流量,因此它们可以更快地进行插入和更新。有时值得将一堆数据放入临时表中,然后根据需要进行操作,然后执行TRUNCATE TABLE blah;将其复制到最终表中。请注意,临时表是每个会话;如果你的会话结束或你的连接丢失,那么临时表就会消失,没有其他连接可以看到会话的临时表的内容。

如果你正在使用PostgreSQL 9.1或更新版本,你可以使用virtual memory subsystem表来获取丢失的数据,例如会话状态。这些在不同的会话中可见,并在连接之间保留。如果服务器不正常地关闭它们就会被截断,这样它们就无法用于任何你可以重新创建的东西,但它们对于缓存,物化视图,状态表等都很有用。

一般来说,不要TRUNCATE。请改用TRUNCATES;当您将所有行转储到表中时,它会快得多。如果可以,在一个DELETE调用中截断许多表。如果你一遍又一遍地做很多DELETE个小桌子,那么会有一个警告;见:UNLOGGED

如果您没有外键索引,那么涉及这些外键引用的主键的TRUNCATE将会非常慢。如果您期望从引用的表中{{1}},请确保创建此类索引。 {{1}}不需要索引。

不要创建您不需要的索引。每个指数都有维护成本。尝试使用最小的索引集,让位图索引扫描结合它们,而不是维护太多庞大,昂贵的多列索引。如果需要索引,请先尝试填充表,然后在最后创建索引。

硬件

如果你可以管理它,拥有足够的RAM来容纳整个数据库是一个巨大的胜利。

如果你没有足够的内存,你可以获得更快的存储速度。即使是廉价的SSD也会对旋转生锈产生巨大影响。不要相信便宜的SSD用于生产,但它们通常不会崩溃并且可能会占用您的数据。

学习

格雷格史密斯的书Postgresql Truncation speed仍然相关,尽管提到了一个较旧的版本。它应该是一个有用的参考。

加入PostgreSQL通用邮件列表并关注它。

读:

答案 1 :(得分:9)

使用不同的磁盘布局:

  • $ PGDATA的不同磁盘
  • $ PGDATA / pg_xlog
  • 的不同磁盘
  • tem文件的不同磁盘(每个数据库$ PGDATA / base // pgsql_tmp)(请参阅有关work_mem的说明)

postgresql.conf调整:

  • shared_memory:可用内存的30%但不超过6到8GB。对于写密集型工作负载来说,拥有更少的共享内存(2GB - 4GB)似乎更好。
  • work_mem:主要用于具有排序/聚合的选择查询。这是每个连接设置,查询可以多次分配该值。如果数据不适合则使用磁盘(pgsql_tmp)。检查“解释分析”以查看您需要多少内存
  • fsync和synchronous_commit:默认值是安全的,但如果您可以容忍数据丢失,那么您可以关闭然后关闭
  • random_page_cost:如果你有SSD或快速RAID阵列,你可以将其降低到2.0(RAID)甚至更低(1.1)的SSD
  • checkpoint_segments:您可以更高32或64并将checkpoint_completion_target更改为0.9。较低的值允许更快的崩溃后恢复