功能表现


46

由于MySQL的背景,存储过程的性能(较旧的文章)可用性令人怀疑,我正在为我的公司评估PostgreSQL的新产品。

我想做的一件事是将一些应用程序逻辑移到存储过程中,因此我在这里要求在PostgreSQL(9.0)中使用函数时应做的DO和不做的(最佳实践),特别是关于性能陷阱。


你的意思是你不想要的答案提什么表现有关?
杰克·道格拉斯

克里斯·特拉弗斯(Chris Travers)关于使用存储过程的优点的博客很多,例如,这里:ledgersmbdev.blogspot.de/2012/07/…和这里:ledgersmbdev.blogspot.de/2012/07/…只是浏览他的博客,有一个关于这个主题的很多有趣的文章。
a_horse_with_no_name

Answers:


51

严格来说,术语“存储过程”指向Postgres 11中引入的Postgres中的SQL过程

还有一些功能,几乎可以完成,但不完全相同,而这些功能从一开始就存在。

功能LANGUAGE sql基本上与一个函数包装纯SQL命令(以及因此原子,总是一个内运行刚批处理文件单个事务)接受参数。SQL函数中的所有语句都是立即计划,这与在另一个语句之后执行一个语句有细微的差别,并且可能会影响获取锁的顺序。

除此之外,最成熟的语言是PL / pgSQLLANGUAGE plpgsql)。它运行良好,并且在过去十年中的每个发行版中都得到了改进,但它最适合用作SQL命令的粘合剂。它不用于繁重的计算(SQL命令除外)。

PL / pgSQL函数执行查询,如准备好的语句。重用缓存的查询计划可以减少一些计划开销,并使它们比等效的SQL语句快一点,这可能会因情况而产生明显的影响。它也可能有类似以下相关问题的副作用:

此携带的优点和准备语句的缺点- 在手动讨论。对于具有不规则数据分布和可变参数的表的查询,当针对给定参数的优化执行计划获得的收益超过重新计划的成本时,动态SQL的性能EXECUTE可能会更好。

由于Postgres 9.2的通用执行计划仍在会话中缓存,因此请引用手册

对于没有参数的准备好的语句,这种情况立即发生;否则,只有在五个或更多执行生成计划的估算平均成本(包括计划间接费用)比通用计划成本估算贵得多的计划之后,才会发生这种情况。

大多数情况下,我们在不(ab)使用的情况下(最好不要花费额外的开销)两全其美EXECUTEPostgreSQL Wiki的PostgreSQL 9.2的新增功能中的详细信息

Postgres 12引入了附加服务器变量plan_cache_mode来强制执行通用或自定义计划。对于特殊情况,请小心使用。

服务器端的功能可以防止应用程序与数据库服务器进行额外的往返,从而赢得巨大的成功。让服务器一次执行尽可能多的操作,仅返回定义良好的结果。

避免嵌套复杂的函数,尤其是表函数(RETURNING SETOF recordTABLE (...))。函数是黑匣子,构成了查询计划者的优化障碍。它们是分开优化的,而不是在外部查询的上下文中进行的,这使计划变得更简单,但可能会导致计划不尽人意。而且,功能的成本和结果大小无法可靠地预测。

此规则的例外是简单的SQL函数(LANGUAGE sql),如果满足某些先决条件,则可以“内联”。在Neil Conway的这篇演讲中,了解有关查询计划器工作原理的更多信息(高级知识)。

在PostgreSQL中,函数总是自动在单个事务中运行。所有的一切都成功了,还是没有成功。如果发生异常,则所有内容都会回滚。但是有错误处理 ...

这就是为什么函数完全是“存储过程”的原因(即使有时会误用该术语)。一些命令喜欢VACUUMCREATE INDEX CONCURRENTLYCREATE DATABASE不能在事务块内运行,因此它们没有在功能不允许的。(从Postgres 11开始,SQL过程中都没有。以后可能会添加。)

这些年来,我已经编写了数千个plpgsql函数。


2
@nhahtdh:“自动交易”不是技术术语。在我澄清之后,这只是一种几乎不优雅的表达方式。根本不是自主交易。“自治”恰好是一个类似的词。
Erwin Brandstetter 2015年

4
从这里开始的答案可能是史诗般的PostGreSQL最佳实践手册。
达沃斯

10

一些DO:

  • 尽可能使用SQL作为函数语言,因为PG可以内联语句
  • 正确使用IMMUTABLE / STABLE / VOLATILE,因为PG可以将结果保持不变或稳定,因此可以缓存结果
  • 正确使用STRICT,因为PG可以在任何输入为null时返回null而不是运行该函数
  • 当您不能使用SQL作为函数语言时,请考虑使用PL / V8。在我运行的一些不科学的测试中,它比PL / pgSQL快
  • 将LISTEN / NOTIFY用于可能长时间运行的进程,这些事务可能会在事务外发生
  • 考虑使用函数来实现分页,因为基于键的分页可能比基于LIMIT的分页更快
  • 确保对功能进行单元测试

这是我第一次看到PL / V8比PL / pgSQL更快的说法。您是否有(已发布的)数据来支持这一点?
a_horse_with_no_name 2013年

@a_horse_with_no_name不,我不知道。就像我说的,我做了一些不科学的测试。它们主要是逻辑,而不是数据访问。我会在圣诞节期间尝试进行一些可重复的测试,然后在此处重新发布。
尼尔·麦圭根

@a_horse_with_no_name这是FizzBu​​zz plv8 vs plpgsql的一个快速实用的示例:blog.databasepatterns.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan

8

一般而言,将应用程序逻辑移入数据库将意味着它更快-毕竟它将在数据附近运行。

我相信(但不是100%肯定)SQL语言功能比使用任何其他语言的功能要快,因为它们不需要上下文切换。缺点是不允许程序逻辑。

PL / pgSQL是内置语言中最成熟,功能最完整的-但是出于性能考虑,可以使用C(尽管它只会使计算密集型功能受益)


7

您可以使用postgresql中的用户定义函数(UDF)做一些非常有趣的事情。例如,您可以使用多种语言。内置的pl / sql和pl / pgsql既强大又可靠,并使用沙盒方法来阻止用户执行任何非常危险的事情。用C编写的UDF在与数据库本身相同的上下文中运行,从而为您提供了最大的功能和性能。但是,这就像在玩火,因为即使是很小的错误也会导致巨大的问题,后端崩溃或数据损坏。定制pl语言(例如pl / R,pl / ruby​​,pl / perl等)使您能够用相同的语言编写数据库层和应用程序层。这可能很方便,因为这意味着您不必教Perl程序员Java或pl / pgsql等来编写UDF。

最后,有pl / proxy语言。使用此UDF语言,您可以在数十个或更多后端Postgresql服务器上运行应用程序以进行扩展。它是由Skype的好人开发的,基本上允许穷人的水平缩放解决方案。写起来也很容易。

现在,关于性能问题。这是灰色区域。您是否正在为一个人编写应用程序?还是1000?还是一千万?构建应用和使用UDF的方式将取决于您尝试扩展的方式。如果您要为成千上万的用户编写程序,那么您要做的主要事情就是尽可能减少db的负载。UDF可以减少移出和移回数据库的数据量,这将有助于减少IO负载。但是,如果它们开始增加CPU负载,则可能是一个问题。一般来说,降低IO负载是第一要务,其次是确保UDF高效以免使CPU过载。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.