Postgres被低估了—它处理的内容超出您的想象

考虑使用Redis或Elasticsearch等数据存储扩展到Postgres以外的地方?在采用复杂的基础架构之前,请三思。 Postgres可以扩展以应对重载,并提供强大的功能,这些功能乍一看并不明显。例如,可以启用内存中缓存,文本搜索,专用索引和键值存储。

考虑扩展到Postgres集群之外并添加另一个数据存储(例如Redis或Elasticsearch)?在采用更复杂的基础架构之前,请花一分钟时间再三考虑。很有可能从现有的Postgres数据库中获得更多收益。它可以扩展以应对重载,并提供强大的功能,这些功能乍一看并不明显。例如,可以启用内存中缓存,文本搜索,专用索引和键值存储。

阅读本文之后,您可能想从数据存储中列出所需的功能,并检查Postgres是否适合它们。它足以应付大多数应用。

为什么添加另一个数据存储并不总是一个好主意

正如弗雷德·布鲁克斯(Fred Brooks)在《神话人月》中所说的那样:“程序员,就像诗人一样,只需要从纯粹的思想中移除一点。(他们)通过发挥想象力在空中,空中建造城堡。”

为这些城堡增加更多的零件,并迷失在设计中,这是无穷的魅力。但是,在现实世界中,空中建造更多的城堡会妨碍您的前进。数据存储中的最新炒作也是如此。选择无聊的技术有几个优点:

  • 如果有新人加入您的团队,他们可以轻松地理解您的不同数据存储吗?
  • 一年后,当您或另一个团队成员回来时,他们是否可以迅速掌握系统的工作原理?
  • 如果您需要更改系统或添加功能,则需要移动几块?
  • 您是否考虑了维护成本,安全性和升级?
  • 在大规模生产中运行新数据存储时,您是否考虑了未知和失败模式?

尽管可以通过周到的设计进行管理,但是添加多个数据存储确实会增加复杂性。在探索添加其他数据存储之前,值得研究一下现有数据存储可以为您提供哪些附加功能。

Postgres鲜为人知但功能强大的功能

许多人没有意识到Postgres提供的不仅仅是SQL数据库。如果堆栈中已经有Postgres,为什么在Postgres可以完成这项工作时又添加更多的零件?

Postgres缓存

有一个误解,认为Postgres会在每次查询时从磁盘上读写数据,特别是当用户将其与Redis等纯粹的内存数据存储进行比较时。

实际上,Postgres有一个设计精美的缓存系统,其中包含页面,使用计数和事务日志。您的大多数查询都不需要访问磁盘,尤其是当它们反复查询相同的数据时(尤其是许多查询倾向于这样做)。

Postgres配置文件中的shared_buffer配置参数确定它将用于缓存数据的内存量。通常,应将其设置为总内存的25%到40%。这是因为Postgres还使用操作系统缓存进行操作。有了更多的内存,大多数引用相同数据集的重复查询将不需要访问磁盘。您可以通过以下方法在Postgres CLI中设置此参数:

ALTER SYSTEM SET shared_buffer TO = <value>

诸如Heroku之类的托管数据库服务提供了几种计划,其中RAM(以及缓存)是主要区别。免费的业余版本不提供诸如RAM之类的专用资源。准备好进行生产负载时进行升级,以便可以更好地利用缓存。

您还可以使用一些更高级的缓存工具。例如,检查pg_buffercache视图以查看实例所占用的共享缓冲区缓存。另一个要使用的工具是pg_prewarm函数,它是基础安装的一部分。此功能使DBA可以将表数据加载到操作系统缓存或Postgres缓冲区缓存中。该过程可以是手动或自动的。如果您知道数据库查询的性质,则可以大大提高应用程序性能。

对于真正Brave人,请参阅本文以深入了解Postgres缓存。

文字搜寻

Elasticsearch非常出色,但是许多用例可以与Postgres很好地进行文本搜索。 Postgres具有特殊的数据类型, tsvector,以及一组功能,例如 to_tsvectorto_tsquery,以快速搜索文本。 tsvector 表示通过对术语进行排序和规范化变体对文本搜索进行优化的文档。这是一个例子 to_tsquery 功能:

SELECT to_tsquery('english', 'The & Boys & Girls');

  to_tsquery   
---------------
 'boy' & 'girl'

您可以根据相关性对查询结果进行排序,具体取决于查询在查询结果中出现的频率和字段。例如,您可以使标题比正文更相关。有关详细信息,请查阅Postgres文档。

Postgres中的函数

Postgres提供了多种编程语言的强大的服务器端功能环境。

尝试使用服务器端功能在Postgres服务器上尽可能多地预处理数据。这样,您可以减少在应用程序服务器和数据库之间来回传递过多数据所带来的延迟。此方法对于大型聚合和联接特别有用。

更好的是,您的开发团队可以利用其现有的技能来编写Postgres代码。除了默认的PL / pgSQL(Postgres的本地过程语言)以外,Postgres的函数和触发器可以用PL / Python,PL / Perl,PL / V8(Postgres的JavaScript扩展)和PL / R编写。

这是创建用于检查字符串长度的PL / Python函数的示例:

CREATE FUNCTION longer_string_length (string1 string, string2 string)
  RETURNS integer
AS $$
  a=len(string1)
  b-len(string2)
  if a > b:
    return a
  return b
$$ LANGUAGE plpythonu;

Postgres提供强大的扩展

对Postgres的扩展是插件在许多应用程序中的含义。适当使用Postgres扩展程序也可能意味着您无需与其他数据存储一起使用即可获得额外的功能。有很多可用的扩展名,并在Postgres主网站上列出了。

地理空间数据

PostGIS是Postgres的专门扩展,用于地理空间数据操作和SQL中的运行位置查询。它在使用Postgres的GIS应用程序开发人员中广受欢迎。可以在这里找到有关使用PostGIS的入门指南。

下面的代码段显示了我们如何将PostGIS扩展添加到当前数据库中。在操作系统上,我们运行以下命令来安装软件包(假设您使用的是Ubuntu):

$sudo add-apt-repository ppa:ubuntugis/ppa
$sudo apt-get update
$sudo apt-get install postgis

之后,登录到您的Postgres实例并安装扩展:

CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;

如果要检查当前数据库中具有哪些扩展名,请运行以下命令:

SELECT * FROM pg_available_extensions;

键值数据类型

Postgres hstore扩展允许存储和搜索简单的键值对。本教程很好地概述了如何使用hstore数据类型。

半结构化数据类型

在Postgres中有两种用于存储半结构化数据的本机数据类型:JSON和XML。 JSON数据类型可以承载本机JSON及其二进制格式(JSONB)。搜索后,后者可以显着提高查询性能。如下所示,它可以将JSON字符串转换为本地JSON对象:

SELECT '{"product1": ("blue", "green"), "tags": {"price": 10, "discounted": false}}'::json;

json                       
---------------------------------------------------------------------
 {"product1": ("blue", "green"), "tags": {"price": 10, "discounted": false}}

扩展Postgres的技巧

如果您出于性能原因考虑关闭Postgres,请先查看其提供的优化功能。在这里,我们假设您已经完成了基础工作,例如创建适当的索引。 Postgres提供了许多高级功能,尽管更改很小,但可以带来很大的不同,特别是如果它使您避免基础架构复杂化。

不要过度索引

避免不必要的索引。谨慎使用多列索引。过多的索引占用了额外的内存,从而无法更好地利用Postgres缓存,这对性能至关重要。

使用类似的工具 EXPLAIN ANALYZE 查询计划器实际选择顺序表扫描的频率可能会让您感到惊讶。由于您表格的许多行数据已经被缓存,因此通常甚至不使用这些复杂的索引。

就是说,如果您发现查询速度慢,第一个也是最明显的解决方案是查看表是否缺少索引。索引至关重要,但是您必须正确使用它们。

部分索引节省空间

部分索引可以通过指定要索引的值来节省空间。例如,您想按用户的注册日期进行订购,但只关心已注册的用户:

CREATE INDEX user_signup_date ON users(signup_date) WHERE is_signed_up;

了解Postgres索引类型

为数据选择正确的索引可以提高性能。以下是一些常见的索引类型以及何时应使用每种索引类型。

  • B树索引
    B树索引是用于有效排序数据的二叉树。如果您使用 INDEX 命令。大多数时候,B树索引就足够了。在扩展时,不一致可能是一个更大的问题,因此请定期使用amcheck扩展名。
  • BRIN指数
    当表格自然已经按列排序时,可以使用块范围索引(BRIN),而您需要按该列排序。例如,对于顺序写入的日志表,在timestamp列上设置BRIN索引可让服务器知道数据已被排序。
  • 布隆过滤器指数
    Bloom索引非常适合只需要测试相等性的大表上的多列查询。它使用一种称为布隆过滤器的特殊数学结构,该结构基于概率并且使用的空间大大减少。
 CREATE INDEX i ON t USING bloom(col1, col2, col3);
 SELECT * from t WHERE col1 = 5 AND col2 = 9 AND col3 = 'x';
  • GIN和GiST索引
    将GIN或GiST索引用于基于Compound值(例如文本,数组和JSON)的有效索引。

什么时候需要另一个数据存储?

有合理的理由添加除Postgres之外的另一个数据存储。

特殊数据类型

一些数据存储为您提供了Postgres无法获得的数据类型。例如,Redis中的链接列表,位图和HyperLogLog函数在Postgres上不可用。

在上一次启动时,我们必须实现频次上限,该上限是针对基于会话数据(例如Cookie)的网站上唯一身份用户的计数器。可能有数百万或数千万的用户访问网站。展示频率上限意味着您每天只向每个用户展示一次您的广告。

Redis的HyperLogLog数据类型非常适合频率上限。它以非常小的错误率来近似集成员身份,以换取O(1)时间和非常小的内存占用。 PFADD 将元素添加到HyperLogLog集。如果您的元素尚未在集合中,则返回1,如果它不在集合中,则返回0。

PFADD user_ids uid1
(integer) 1
PFADD user_ids uid2
(integer) 1
PFADD user_ids uid1
(integer) 0

繁重的实时处理

如果您遇到许多发布事件,工作和数十名工作人员需要协调的情况,则可能需要更专业的解决方案,例如Apache Kafka。 LinkedIn工程师最初是开发Kafka来处理新的用户事件,例如单击,邀请和消息,并允许不同的工作人员处理消息传递和作业来处理数据。

即时全文搜索

如果您的实时应用程序负载沉重,一次要进行十次以上的搜索,并且需要自动完成等功能,那么您可能会从Elasticsearch这样的专用文本解决方案中受益匪浅。

结论

Redis,Elasticsearch和Kafka功能强大,但是有时添加它们弊大于利。利用我们这里介绍的鲜为人知的功能,您也许可以使用Postgres获得所需的功能。确保充分利用Postgres可以节省您的时间,并有助于避免增加复杂性和风险。

为了节省更多时间和头痛,请考虑使用诸如Heroku Postgres之类的托管服务。扩大规模很简单,只需添加其他关注者副本即可,只需单击即可打开高可用性,Heroku会为您进行操作。如果您确实需要扩展到Postgres之外,那么我们上面提到的其他数据存储(例如Redis,Apache Kafka和Elasticsearch)都可以在Heroku上轻松配置。继续并在空中建造您的城堡-但将它们固定在可靠的基础上,这样您就可以梦想获得更好的产品和客户体验。

有关Postgres的更多信息,请收听《软件工程日报》上与Jon Daniel的Cloud Database Workloads。

资讯来源:由0x资讯编译自DEV,原文:https://dev.to/heroku/postgres-is-underrated-it-handles-more-than-you-think-4ff3 ,版权归作者所有,未经许可,不得转载
你可能还喜欢