CYBERTEC PostgreSQL Logo

更轻松地进行 PostgreSQL 调试

Hans-Jürgen Schönig 03.2025 / Category: How To / Tags: development

PostgreSQL 是成千上万应用程序的基础。该系统长期以来已被证明其价值并可靠运行。但是,人们经常问的问题是:调试数据库应用程序的最佳方法是什么?

目录:

多年来,我一直在使用一种简单的方法,可以大大加快典型应用程序的调试过程。

使用继承来存储数据

PostgreSQL 的核心功能之一,已经存在了几十年,是 “继承” 的概念。那到底是什么意思呢?简单来说,表可以相互继承列。子表将简单地拥有父表的所有列,以及它自己的附加列。

但这在现实生活中意味着什么,它与调试有什么关系?让我们仔细看看:

CREATE TABLE t_global (
    id serial,
    tstamp timestamptz DEFAULT now()
);

CREATE TABLE t_product (
    name text,
    price numeric
) INHERITS (t_global);

INSERT INTO t_product (name, price) VALUES
('Shoes', 113.98),
('Sausage', 4.58);

t_global 表包含一个序列,包括一个时间戳。这两个列传递给 t_product。这意味着该序列现在也适用于子表。

这是第二个表:

CREATE TABLE t_country (
    country_name text
) INHERITS (t_global);

INSERT INTO t_country (country_name) VALUES
('Austria'),
('Germany'),
('Japan');

我们现在将相同的父表用于国家/地区表。这有什么关系?我们刚刚产生了两个结果:首先,所有表都有一个全局序列,这意味着整个系统中的所有 ID 都是唯一的(我们稍后会需要它)。另外:所有表都有一个具有相同默认值的时间戳。

使用父表来调试应用程序

现在让我们想象一下,我们要调试一个应用程序,并且想知道两件事:

我们刚刚创建的结构使回答这两个问题变得非常容易:

test=# SELECT tableoid::regclass, * FROM t_global;
  tableoid  | id |             tstamp
-----------+----+-------------------------------
 t_product |  1 | 2025-01-24 12:02:07.295524+01
 t_product |  2 | 2025-01-24 12:02:07.295524+01
 t_country |  3 | 2025-01-24 12:02:07.295524+01
 t_country |  4 | 2025-01-24 12:02:07.295524+01
 t_country |  5 | 2025-01-24 12:02:07.295524+01
(5 rows)

请记住,只有一个序列提供所有 ID 列,因此我们可以依靠 ID 在整个数据库中都是唯一的事实。但是还有更多:在 PostgreSQL 中,每个表都支持一个名为 "tableoid" 的虚拟列。它显示了表的对象 ID。现在的技巧如下:如果我们将此对象 ID 转换为一种特殊的数据类型 (= regclass),它将为我们提供表名的字符串表示形式。换句话说,我们可以运行一个 SQL 语句,它将为我们提供整个系统中的所有 ID,包括包含此 ID 的表名。在整个应用程序中,所有内容都是唯一的事实的支持下,我们可以轻松地找出在哪里可以找到我们可能正在寻找的任何东西。

但是,我们可能想仔细查看第二列:时间戳。请注意,所有时间戳都相同。之所以如此,是因为所有数据都是由同一事务写入的。乍一看,我们可以看到数据的插入顺序,同时,我们可以看到这是否发生在同一事务中。一直以来,我们仍然可以完全了解跨所有表的数据更改顺序。

这篇文章中概述的方法对我有用了很多年,并且使我调试数据库方面的工作变得容易得多。因此,我希望这对其他人也有所帮助。

您是否需要对您的 PostgreSQL 请求提供支持? 我们将很乐意为您提供帮助。 直接联系我们