Postgresql的Extensions能够延伸,更改和推进Postgres的行为。怎么样?通过hooking到底层的Postgres API hooks。
开源的Citus数据库水平扩展了Postgres,它本身就是一个PostgreSQL扩展,它允许Citus保持最新的Postgres版本,而不会像其他Postgres分*样落后。
尽管我以前已经写过各种类型的扩展,但是今天我想更深入地了解最有用的Postgres扩展:pg_stat_statements。
如你所见,我刚从FOSDEM回来。 FOSDEM是在布鲁塞尔举行的年度免费开源软件会议,在活动中,我在PostgreSQL开发室中发表了有关Postgres扩展的演讲。
到今天结束时,Postgres开发室中进行的一半以上的讨论都提到了pg_stat_statements:
Most frequently dispensed #PostgreSQL tip-of-the-day here in the Postgres devroom at #FOSDEM? Use pg_stat_statements! @Xof’s talk on Breaking PostgreSQL at Scale is the 4th talk today to drive this point home HT @craig @net_snow @magnushagander pic.twitter.com/Tcwkhy8W8h
— Claire Giordano (@clairegiordano) February 3, 2019
如果您使用Postgres,但尚未使用pg_stat_statements,则必须将其添加到工具箱中。即使您很熟悉,也可能值得回顾一下。
pg_stat_statements入门
pg_stat_statements是所谓的contrib扩展名,可以在PostgreSQL发行版的contrib目录中找到。
这意味着它已经随Postgres一起提供了,您不必从源代码构建它或安装软件包。如果尚未启用数据库,则可能必须启用它。这很简单:
CREATE EXTENSION pg_stat_statements;
如果您在主要的云提供商上运行,则很有可能他们已经为您安装并启用了它。
一旦安装了pg_stat_statements,它就会开始悄悄地在后台运行。 Pg_stat_statements记录针对您的数据库运行的查询,从中删除许多变量,然后保存有关该查询的数据,例如花费了多长时间以及基础读/写发生了什么。
注意:它不会保存每个查询,而是对其进行参数化,然后保存汇总结果
让我们来看几个示例。假设我们执行以下查询:
SELECT order_details.qty, order_details.item_id, order_details.item_price FROM order_details, customers WHERE customers.id = order_details.customer_id AND customers.email = ‘craig@citusdata.com‘
它将查询转换为:
SELECT order_details.qty, order_details.item_id, order_details.item_price FROM order_details, customers WHERE customers.id = order_details.customer_id AND customers.email = ‘?‘
如果这是我在应用程序中经常执行的查询,以获取诸如零售订单历史记录之类的订单详细信息,那么它不会简化我为每个用户运行该订单的频率数据,而是通过汇总视图来简化存储。
观察pg_stat_statements数据
SELECT * FROM pg_stat_statements; userid | 16384 dbid | 16388 query | select * from users where email = ?; calls | 2 total_time | 0.000268 rows | 2 shared_blks_hit | 16 shared_blks_read | 0 shared_blks_dirtied | 0 shared_blks_written | 0 local_blks_hit | 0 local_blks_read | 0 local_blks_dirtied | 0 local_blks_written | 0
汇总pg_stat_statements历史记录
现在,这里有大量有价值的信息,作为高级用户,有时它们都可以证明是有价值的。
但是,即使没有开始了解数据库的内部结构,您仍然可以通过以某些方式查询pg_stat_statements来获得一些真正强大的见解。
通过查看total_time和每个查询被调用一次的次数,我们可以非常快速地了解哪些查询经常运行以及它们平均消耗了多少:
SELECT (total_time / 1000 / 60) as total, (total_time/calls) as avg, query FROM pg_stat_statements ORDER BY 1 DESC LIMIT 100;
您可以采用多种不同的方式来对此进行过滤和排序,您可能只希望关注运行1000次以上的查询。或平均超过100毫秒的查询。
上面的查询向我们显示了数据库消耗的总时间(以分钟为单位)以及平均时间(以毫秒为单位)。
通过上面的查询,我会得到如下所示的内容:
total | avg | query --------+--------+------------------------- 295.76 | 10.13 | SELECT id FROM users... 219.13 | 80.24 | SELECT * FROM ... (2 rows)
根据经验,我知道在快速获取记录时,PostgreSQL应该能够在1ms内返回。
鉴于此,我可以开始优化工作。在上面的内容中,我看到将第一个查询降低到1ms会有所改善,但是优化第二个查询将使我的系统整体性能得到更大的提升。
特别说明:如果要构建多租户应用,则可能不希望pg_stat_statements参数化tenant_id。为了解决这个问题,我们构建了citus_stat_statements来为每个租户提供见解。
如果您从未(甚至在过去的一个月中)都没有查看过pg_stat_statements中的数据,那么今天对您来说是个好日子。
它可以告诉您哪些地方可以优化?我们希望听到您发现@citusdata的内容。
享受您正在阅读的内容吗?
如果您有兴趣阅读我们团队的更多帖子,请注册我们的每月时事通讯,并将最新内容直接发送到您的收件箱。
译者注:
1,原来类似功能就叫做“Extensions”,打开后就是记录历史SQL执行代价的汇总信息。
2,Postgresql中的pg_stat_statements有点类似于MySQL中的general query log,或者sqlserver中的执行计划缓存sys.dm_exec_query_stats,他是基于移除参数的sql做模板,直接汇总了一个SQL的调用以及消耗情况
3,不清楚pg_stat_statements可以设置筛选条件,类似于sqlserver中的扩展事件,比如可以基于库,用户,或者语句,或者超出一定时间的语句做筛选,目前这种记录方式说实话参考意义有限。
4,开启了pg_stat_statements之后,对性能有多大的影响?
5,如何清理或者自定义的方式重置pg_stat_statements中的历史记录?