优化PostgreSQL以进行快速测试

Dmy*_*iak 196 sql database postgresql performance database-tuning

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

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

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

从头到尾有几件显而易见的事情是:

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

你可能已经明白我不关心可靠性和其余的(DB在这里只是一次性的东西).
我需要充分利用PG并尽可能快地完成它.

理想情况下,最佳答案将描述这样做的技巧,设置和这些技巧的弊端.

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

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

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

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

为了"修复"它,我在每次测试之前打开一个事务并在结束时回滚它.

约700个测试的一些数字.

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

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

Cra*_*ger 271

首先,始终使用最新版本的PostgreSQL.性能改进总是会到来,所以如果您正在调整旧版本,那么您可能会浪费时间.例如,PostgreSQL 9.2显着提高了速度TRUNCATE,当然还增加了仅索引扫描.甚至应该遵循轻微的释放; 看版本政策.

注意事项

千万不要把表放在ramdisk上或其他非耐久存.

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

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

PostgreSQL服务器配置

测试时,您可以将服务器配置为非持久但更快的操作.

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

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

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

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

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

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

如果你正在使用一些只需要做大量工作的连接,那就增加work_mem它们以便为它们提供更多的RAM等等.请注意,work_mem设置太高会导致内存不足问题,因为它不是排序每个连接,因此一个查询可以有许多嵌套排序.你只有真正有提高work_mem,如果你能看到各种各样的溢出到磁盘EXPLAIN或登录log_temp_files设置(推荐),但具有较高的价值也可以让皮克挑聪明的计划.

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

最后,调整您的查询.确保您的random_page_costseq_page_cost反映您的系统性能,确保您effective_cache_size的正确性等.EXPLAIN (BUFFERS, ANALYZE)用于检查单个查询计划,并打开auto_explain模块以报告所有慢速查询.通过创建适当的索引或调整成本参数,您通常可以显着提高查询性能.

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

主机OS调整

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

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

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

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

在较新的内核上,您可能希望确保将vm.zone_reclaim_mode其设置为零,因为与PostgreSQL管理的方式相互作用会导致NUMA系统(目前大多数系统)出现严重的性能问题shared_buffers.

查询和工作负载调整

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

如果您没有将工作分配到更大的事务中,请启动.很多小交易都很昂贵,所以你应该在可能和实际的情况下批量处理.如果您使用的是异步提交,则不太重要,但仍然强烈推荐.

尽可能使用临时表.它们不会生成WAL流量,因此它们的插入和更新速度要快得多.有时值得将一堆数据插入到临时表中,然后根据需要对其进行操作,然后将INSERT INTO ... SELECT ...其复制到最终表中.请注意,临时表是每个会话; 如果您的会话结束或者您丢失了连接,那么临时表就会消失,其他任何连接都无法看到会话临时表的内容.

如果您使用的是PostgreSQL 9.1或更高版本,则可以使用UNLOGGED表格来处理丢失的数据,例如会话状态.这些在不同的会话中可见,并在连接之间保留.如果服务器不正常地关闭,它们会被截断,因此它们不能用于任何你无法重新创建的东西,但它们非常适合缓存,物化视图,状态表等.

一般来说,不要DELETE FROM blah;.使用TRUNCATE TABLE blah;代替; 当您将所有行转储到表中时,它会快得多.TRUNCATE如果可以,在一个调用中截断许多表.如果你TRUNCATES一遍又一遍地做很多小桌子,那就有一个警告; 看:Postgresql截断速度

如果您没有外键索引,那么DELETE涉及这些外键引用的主键的s将非常慢.如果您DELETE对引用的表有所期望,请确保创建此类索引.索引不是必需的TRUNCATE.

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

硬件

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

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

学习

格雷格史密斯的书,PostgreSQL 9.0高性能仍然相关,尽管有点旧版本.它应该是一个有用的参考.

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

读:

  • 我还可以推荐@GregSmith的PostgreSQL 9.0 High Performance,这真是一个很棒的阅读.本书涵盖了从磁盘布局到查询调优的性能调优的各个方面,让您对PG内部结构有了很好的理解. (10认同)
  • 我没有发布PostgreSQL 9.1的书的更新,这是自出版以来唯一的版本,因为9.1中没有足够的性能相关变化来保证它. (10认同)
  • 很棒的写作.就像一个微小的更新,"你可能需要增加操作系统的最大共享内存限制,如果增加shared_buffers"不再适用于PostgreSQL 9.3下的大多数用户:http://www.postgresql.org/docs/9.3/静态/释放9-3.html#AEN114343 (3认同)

mys*_*mys 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.较低的值允许更快的崩溃后恢复

  • 请注意,如果您已经使用`fsync = off`运行,那么将pg_xlog放在单独的磁盘上就不会有太大改进了. (4认同)