使用PostgreSQL时的典型错误。 第一部分

一个多月前,在莫斯科举行了规模最大的后希腊社区PGConf.Russia 2019会议,在莫斯科国立大学聚集了700多人。 我们决定发布最佳报告的视频和成绩单。 会议上,Ivan Frolkov关于使用PostgreSQL的典型错误的演讲被认为是最佳会议,因此我们将从它开始。

为了方便起见,我们将解密分为两部分。 在本文中,我们将讨论不一致的命名,约束,在数据库或应用程序中最好集中逻辑的位置。 第二部分将处理错误处理,并发访问,不可取消的操作,CTE和JSON。



在我们公司中,我从事与应用程序相关的问题的客户支持,也就是说,在出现连接问题,查询优化和其他类似问题时,我会提供帮助。 我已经看到足够多的最多样化的应用程序。 我只是没看到什么! 甚至比我们想要的还要多。 我要说的部分内容不仅适用于PostgreSQL,而且适用于任何数据库,但主要适用于PostgreSQL。

我能够从我所看到的中得出的主要结论是非常意外的:实际上,任何具有适当持久性的应用程序都可以正常工作。 有一个很棒的项目(我不能说所有与我们合作的公司),其中一个更出色的应用程序创建了数以百万计的表格。 它看起来像这样:在星期一,该系统运行良好,而在星期五,它实际上不起作用。 在周末,他们会推出VACUUM FULL,而在星期一,它将再次运行良好。 事实证明,您可以像这样对PostgreSQL进行模拟,并且所有这些将在相当长的一段时间内有效。 另一个同志做了一件奇怪的事:一切都建立在他身上的触发器上,根本没有任何程序。 也就是说,大多数表不能被触摸,无法完成某些工作,但是这个基础仍然存在。

他这样解释:“基础从一种一致的状态转变为另一种一致的状态。 如果我重新上传数据,它将中断。 但是由于我有触发器和唯一键,所以我无法重新滚动数据。” 这种方法很疯狂,但同时也有一定道理。 也许有必要做些不同的事情,但也有必要考虑到客户的特点。 我要谈论的第一个错误是:



这是我遇到的一个真实例子。 在幻灯片上,您将看到在不同的列中如何命名同一实体。 一个也可以有空格。 其他对象的名称也不一致。 如果需要在另一个表中存储某些内容,则需要查看该表中的内容是否相同。 如果您在同一表中有id_user和user_id,则工作将从研究开始:这将意味着什么。

对于其他客户端,所有对象的命名方式如下:两个字母,然后是五个数字。 我必须说这不是“ 1C”。 他们为什么这么做-我不知道:这没有逻辑,但是优化查询是我的职责。

另一个例子:部分用俄语命名,部分用非俄语命名,但是带有某种俄罗斯口音。 这使理解变得困难,并产生新的错误。 我本人会尝试为列命名,就好像我指望某个服务一样,这些列名称中的哪一个会自动在某些报告中成为普通列名称。 不幸的是,在现实生活中,连贯命名(包括我的名字)都不太成功。 对于集体发展而言,这尤其困难。 但是我们必须努力。



顺序命名的另一个重要原因:对象名称可通过对元数据的请求获得,即名称也是数据。 您将能够编写一个请求,并从数据库中选择所有图片,例如通常所有图片。



清除元数据非常方便。 尤其是当您考虑文档的典型问题时,以我的经验,文档通常不存在,不完整或不正确,或两者兼而有之:因为编写良好文档的任务在复杂性上与编写代码本身的任务相当。 因此,当代码具有自记录功能时,效果会更好。 逻辑上一致的对象命名有助于实现这一点,当不清楚的地方时,您必须编写代码片段并观察其工作方式。 一无所有,一无所有,但是整天都在做,令人筋疲力尽。



真实案例:我们与之合作的一个非常认真的组织有一个基于Oracle的工作流。 我们将其移至Postgres。 合同的其中一项条款是我们施加外键。 它们不在那儿,不幸的是,我们无法强加它们:事实证明这些表有很多“左”行,没有人知道如何处理它们,包括客户。

当您不需要查看进度条,而需要使用付款文档时,情况就很糟糕。 当根据合同,程序员自己支付错误时,这很有用,并且希望金额很大-然后在几分钟之内(可能是十五分钟)发生启发。 约束立即出现,所有内容立即开始检查。

您甚至都没有想到(嗯,也许有人已经想像)处理付款失败而不是通过但失败的情况要方便得多。 特别是如果量很大。 这是根据个人经验。



另一方面,人们经常可以听到这种限制会降低性能。 是的,它们确实可以,但是如果您想要正确的数据,那么根本就没有其他选择。 如果您的应用程序考虑了顾客对商店的光顾次数,那么可能会有一些不准确之处尤其不会影响统计数据,并且如果我们数钱的话,就必须加以限制。

约束名称通常是由ORM或系统生成的,通常没有人专门打扰命名约束,但是徒劳! 当继续处理错误时,可以通过约束的名称向用户提供明确的消息,对错误进行分类,并让您知道是再次尝试执行该操作,还是不再需要执行该操作,或者根本无法重复该操作。

我没有看到的另一件事,但我强烈建议:对于所有重要的财务(而不仅仅是财务)审计操作,至少应有两个。 事实是,迟早您会进入某些要更改代码的地方,很可能是您违反了其中一项检查。 然后第二个将拯救您。 如果您执行三项,那么也不错。



问题经常出现:在哪里检查数据的正确性。 在客户端还是在服务器上? 在我看来,很明显,您需要在那里检查。 您的客户端有错误,则服务器没有
会丢失,或者服务器上有错误,那么至少客户端会帮助跟踪它。 这个问题有些值得商and,我们顺理成章地讨论了以下主题:在应用程序或数据库中保留基本逻辑的位置?

在数据库中使用它很方便,因为根据我的经验,一家企业会定期发布紧急更改:删除或插入此更改,然后再插入。 如果编译后的代码中包含逻辑,则需要收集,部署并查看发生的情况。 通常这根本是不可能的。 在数据库中,这更方便。 但是有一种众所周知的格言:经验丰富的Fortran程序员以任何语言编写Fortran。 大约80种服务器代码是以完全过程性的方式编写的:我们具有函数“ get_user()”,它返回类型“ user”,如果是“ get_list_users()”,则它返回一个“用户”数组。 用Java编写这样的东西确实比用SQL或pgsql方便得多。



另一方面:为什么需要“ get_user()”功能? 您只需将其放在表格或视图中即可。 由于您具有关系数据库,因此在我看来,您需要编写关系数据库。 首先,重要的是要清楚地确定我们正在使用的数据:如果我们的数据是垃圾或半垃圾,那么结果将是适当的,并且可能不应该被杀死。 如果数据对我们很重要,无论是金钱,财产还是法律运作,那么就需要约束,而且它越好。 我再说一遍:最好不要执行该操作,而不要执行不正确的操作。 并且不要在关系数据库中编写过程代码:您将非常后悔。



我看到一个有3万行(产品)的表,其中“显示相关商品清单”的请求执行了大约一秒钟。 显然,他们设法创建了“美丽而复杂”的数据库架构。 我个人认为,如果您做的事情很棘手,那么很可能是您做错了什么,或者您确实有非常非常困难的任务。 如果您有某种商店或会计人员的常规应用程序,那么实体之间不太可能存在非常复杂的关系。

当我开始职业生涯时,银行系统中60兆字节DBF文件中的表似乎很大,现在60兆字节根本不算什么-硬件更好,软件更好,一切运行得更快,但是问题仍然存在:您从哪里得到这么多数据? 由于档案的原因,很大的,蓬松的底部通常变得如此。 在任何DBMS和PostgreSQL中,都花费了大量的精力来确保一致的应用程序竞争性操作。 归档很可能不会更改,并且根本不需要使用它的大多数DBMS功能。 值得考虑将其从DBMS中删除。



他们时不时地带着目结舌的眼神问这个问题:PostgreSQL会拉这么大个卷的基础吗? 但是这里的问题本身很奇怪:只要有足够的磁盘空间,您就可以将数据尽可能多地放入数据库中。 问题是,例如,如何将存档备份到PB,将完整备份放在哪里以及将要删除多少备份。 我强烈怀疑这些需求量至少部分与设备销售商向您销售更多产品的愿望有关。

如果将文档存储在数据库中,则不太可能在那里进行处理:当然可以在服务器上修改Excel电子表格,但这是一个奇怪的职业。 通常,此类文件通常是只读的。 最好将指向文档的链接及其自身存储在某些外部存储中。 最后,您可以保留表格的数字签名-使其不会更改(如果您决定相关的立法问题)。

另一个观察结果:如果您没有大型企业,而不是某种联邦企业,那么您就不可能拥有庞大的基础。 当然,如果您不将视频存储在其中。



数据库很大的另一个原因是不必要的索引。 没有索引的基数我没有遇到,但是很多时候我遇到了多个基数,这些数个索引以相同的顺序位于同一列上。 该基础允许您执行此操作。 创建索引时,请查看它是否与现有索引重复。 您可以通过查看pg_stat_user_indexes来查看哪些索引是不需要的,以了解如何积极地使用该索引。 也许根本不需要他。

我遇到了一种情况(顺便说一句,典型情况),其中一个超大表未分区。 在所有DBMS中,最好对大表进行分区,但是在PostgreSQL中,由于我们钟爱的VACUUM,尤其如此。 我建议分区表可能以100 GB开头。 也许从50开始。我看到了未分区的兆字节表,但是它们存在于SSD上。 但这有点多,最好切掉它们。



还有一个观察结果:几乎所有大容量数据库都仅附加档案。 在此类数据库中很少能找到实时变化的数据。 拥有什么的决定因素-如果是存档,则可以考虑如何将其保存到某个地方。 而且,顺便说一句,您可以从数据库提供对它的访问。 然后,无需更改应用程序:不会对其进行任何更改。

这些观察中的一些来自“富裕和健康比贫穷和患病更好”类别。 通常,首先是遗留代码。 其次,出乎意料的事情发生了,他们没有考虑任何事情,事实证明一切都没有我们想要的那么美丽。 但尽管如此:不要太聪明。 请记住,如果您很聪明,那么很可能您在做错事。

[待续。]

Source: https://habr.com/ru/post/zh-CN442462/


All Articles