更轻松地进行 PostgreSQL 调试
更轻松地进行 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 都是唯一的(我们稍后会需要它)。另外:所有表都有一个具有相同默认值的时间戳。
使用父表来调试应用程序
现在让我们想象一下,我们要调试一个应用程序,并且想知道两件事:
- 我们要查找的 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 请求提供支持? 我们将很乐意为您提供帮助。 直接联系我们。