优化PostgreSQL进行快速testing

我从一个典型的Rails应用程序从SQLite切换到PostgreSQL。

问题在于PG的运行规格变慢了。
在SQLite上花费了大约34秒,在PG上花了大约76秒, 比慢了2倍多

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

从我头顶上的一些明显的事情是:

  • RAM磁盘(用OSX上的RSpec进行良好的设置很好看)
  • 未logging的表格(可以应用于整个数据库,所以我没有改变所有的脚本?)

正如你可能已经理解,我不关心可靠性和其他(在这里数据库只是一次性的东西)。
我需要充分利用PG,并尽可能快地完成

最好的答案将理想地描述这样做的技巧 ,设置和这些技巧的弊端。

更新: fsync = off + full_page_writes = off只减less时间full_page_writes = off秒(〜-16秒)。 良好的开端,但远不及34的目标。

更新2:我试图使用RAM磁盘,但性能增益是在误差范围内。 所以似乎并不值得。

更新3:*我发现最大的瓶颈,现在我的规格运行速度与SQLite的速度一样快。

问题是做了截断的数据库清理。 显然SQLite太快了。

为了“修复”,我在每次testing之前打开一个交易 ,并在最后回滚。

一些数字〜700testing。

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

SQLite速度提高2倍。 PG的4倍速度增加。

首先,总是使用最新版本的PostgreSQL。 性能改进总是会来的,所以如果你正在调整旧版本,你可能会浪费你的时间。 例如, PostgreSQL 9.2显着提高了TRUNCATE的速度 ,当然还增加了索引扫描。 即使是次要的排放也应该始终遵循。 请参阅版本策略 。

注意事项

不要将表空间放在RAMdisk或其他非持久存储上 。

如果你丢失了一个表空间,整个数据库可能会被损坏,如果没有重要的工作,就很难使用。 与仅使用UNLOGGED表和拥有大量cachingRAM相比,这样做的优势非常小。

如果你真的想要一个基于ramdisk的系统,通过在ramdisk上initdb一个新的PostgreSQL实例,在ramdisk上启动一个全新的集群,所以你有一个完全一次性的PostgreSQL实例。

PostgreSQL服务器configuration

testing时,可以将服务器configuration为非持久但更快的操作 。

这是PostgreSQL中fsync=off设置的唯一可接受的用法之一。 这个设置几乎告诉PostgreSQL不要为了写命令或任何其他令人讨厌的数据完整性保护和崩溃安全性的东西而烦恼,如果你失去电源或者操作系统崩溃,就允许它完全垃圾你的数据。

不用说,除非您使用Pg作为临时数据库,您可以从其他位置重新生成数据,否则不应该在生产中启用fsync=off 。 当且仅当你正在做fsyncclosures也可以closuresfull_page_writes ,因为它不再有任何好处。 请注意, fsync=offfull_page_writes适用于集群级别,因此它们会影响PostgreSQL实例中的所有数据库。

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

如果你可以select稍微修改DDL,那么你也可以使用Pg 9.1+中的UNLOGGED表来完全避免WAL日志logging,并且在服务器崩溃的情况下以代价清除表的代价获得真正的速度提升。 没有configuration选项使所有表未logging,它必须在CREATE TABLE期间设置。 除了做好testing之外,如果您的数据库中包含生成或不重要数据的表格,那么这个数据库中包含的东西需要保证安全,否则这将非常方便。

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

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

如果你只使用了几个连接来完成大量的工作,可以增加work_mem来给它们更多的内存来处理sorting等等。注意,过高的work_mem设置可能会导致内存不足的问题,因为它是per-sorting不是每个连接,所以一个查询可以有很多嵌套sorting。 如果在EXPLAIN可以看到溢出到磁盘的分类,或者使用log_temp_files设置 (推荐)logging,那么只需要增加work_mem ,但是更高的值也可以让Pgselect更聪明的计划。

正如另一张海报所说,如果可能的话,将xlog和主表/索引放在不同的硬盘上是明智的。 单独的分区是毫无意义的,你真的想单独的驱动器。 如果您正在使用fsync=off ,则这种分离的好处会减less很多,如果您使用的是UNLOGGED表,则几乎没有UNLOGGED

最后,调整您的查询。 确保你的random_page_costseq_page_cost反映你系统的性能,确保你的effective_cache_size是正确的。使用EXPLAIN (BUFFERS, ANALYZE)检查单个查询计划,打开auto_explain模块报告所有缓慢的查询。 您通常可以通过创build适当的索引或调整成本参数来大幅提高查询性能。

AFAIK没有办法将整个数据库或群集设置为UNLOGGED 。 能够这样做会很有趣。 考虑在PostgreSQL邮件列表上询问。

主机操作系统调优

您还可以在操作系统级别进行一些调整。 你可能想要做的主要事情是说服操作系统不要积极地把写操作刷新到磁盘上,因为你真的不在乎什么时候把它写到磁盘上。

在Linux中,您可以使用虚拟内存子系统的dirty_*设置来控制这个设置,如dirty_writeback_centisecs

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

这种调整真的需要玩弄设置,看看什么最适合你的工作量。

在较新的内核上,您可能希望确保将vm.zone_reclaim_mode设置为零,因为由于与PostgreSQLpipe理shared_buffers交互,可能会导致NUMA系统(当今大多数系统)出现严重的性能问题。

查询和工作量调整

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

如果您没有将工作分配到更大的交易中,请开始。 很多小额交易都很昂贵,所以只要有可能和实际的情况下,你应该批量加注。 如果你正在使用asynchronous提交,这个不太重要,但仍然强烈build议。

尽可能使用临时表。 他们不会生成WALstream量,所以插入和更新的速度会更快。 有时候,将一堆数据粘贴到一个临时表中,然后按照需要操作它,然后执行INSERT INTO ... SELECT ...将其复制到最终表中。 请注意,临时表是按会话的; 如果你的会话结束,或者你失去了连接,那么临时表将消失,没有其他连接可以看到会话的临时表的内容。

如果您使用的是PostgreSQL 9.1或更高版本,则可以使用UNLOGGED表来处理可能会丢失的数据,例如会话状态。 这些在不同的会话中可见,并在连接之间保留。 如果服务器不干净,它们会被截断,所以它们不能用于任何你不能重新创build的东西,但是对于caching,物化视图,状态表等等来说,它们是非常好的。

一般来说,不要DELETE FROM blah; 。 使用TRUNCATE TABLE blah; 代替; 当您将所有行转储到表中时,速度会更快。 如果可以的话,在一个TRUNCATE调用中截断很多表。 尽pipe如此,如果你一遍又一遍地做很多小桌子的话, 请参阅: Postgresql截断速度

如果你没有外键的索引,那么涉及这些外键引用的主键的DELETE就会非常慢。 如果您希望从引用的表中DELETE ,请确保创build这样的索引。 TRUNCATE不需要索引。

不要创build你不需要的索引。 每个指标都有维护成本。 尝试使用最小的一组索引,让位图索引扫描将它们结合起来,而不是维护太多庞大,昂贵的多列索引。 在需要索引的地方,先尝试填充表格,然后在最后创build索引。

硬件

拥有足够的内存来保存整个数据库是一个巨大的胜利,如果你可以pipe理它。

如果你没有足够的RAM,更快的存储可以变得更好。 即便是廉价的SSD也会对旋转的铁锈产生巨大的影响。 尽pipe不要相信便宜的固态硬盘,但它们通常不会崩溃,可能会吃掉你的数据。

学习

格雷格·史密斯的书, PostgreSQL 9.0高性能仍然是相关的,尽pipe提到了一个较老的版本。 这应该是一个有用的参考。

joinPostgreSQL的一般邮件列表,并按照它。

读:

  • 调整你的PostgreSQL服务器 – PostgreSQL维基
  • 数据库连接数 – PostgreSQL维基

使用不同的磁盘布局:

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

postgresql.conf调整:

  • shared_memory:可用RAM的30%,但不超过6到8GB。 共享内存(2GB – 4GB)的写入密集型工作负载似乎更好
  • work_mem:主要用于具有sorting/聚合的select查询。 这是每个连接设置,并且查询可以多次分配该值。 如果数据不适合,则使用磁盘(pgsql_tmp)。 检查“解释分析”,看看你需要多less内存
  • fsync和synchronous_commit:默认值是安全的,但如果你能容忍丢失的数据,那么你可以closures
  • random_page_cost:如果你有SSD或快速的RAIDarrays,你可以降低到2.0(RAID),甚至更低(1.1)的SSD
  • checkpoint_segments:你可以更高32或64,并将checkpoint_completion_target改为0.9。 较低的值允许更快的故障恢复