Flashback Query in MogDB 3.0

闪回查询可以让使用者查询到以往某个时间点上的表中的内容,这对于某些场合是非常有用处的,甚至是救命的功能。比如如果不小心误删除了表中的数据,就可以通过闪回查询查到删除时间点之前的数据,这样可以直接将这些数据再恢复回来。

比如这样一个让人惋惜的场景(delete的SQL请千万不要在生产环境中运行)。

现在你有这么一张表,记录了账户姓名和账户金额。

MogDB=# select * from accounts;
name | amount
------+--------
A   |   100
B   |   100
C   |   100
D   |     99
(4 rows)

你本来想执行一条SQL,去删除金额等于99元的账户信息。正常执行的话,应该删除1条记录。为了演示效果,先用select来代替delete。

MogDB=#  select * from accounts where amount=99;
name | amount
------+--------
D   |     99
(1 row)

但是在键盘上减号“-”和等号“=”紧挨着,你的手指太胖了,误按到了减号,所以现在你给数据库发出去的命令是这样的。

delete from accounts where amount-99;

为了演示,还是用select来代替delete。

#  select * from accounts where amount-99;
name | amount
------+--------
A   |   100
B   |   100
C   |   100
(3 rows)

恐怖的事情发生了,除了金额真的等于99的那条数据没有返回,其它所有的数据都返回了。也就意味着,如果这是上面的那条delete命令,你删除了表中所有金额不等于99的账户。

好消息是,在MogDB 3.0中,已经修改了对减号这种危险语法的校验,现在执行同样的SQL,将会报错。

MogDB=# delete from accounts where amount-99;
ERROR: argument of WHERE must be type boolean, not type integer
LINE 1: delete from accounts where amount-99;
                                  ^

但是在社区版的openGauss3.0或者MySQL或者MariaDB中,这样的危险语法仍然是可以正常执行的。

gsql ((openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:28:23 commit 0 last mr  release)
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

omm=# select version();
                                        version
--------------------------------------------------------------------------------------------
(openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:28:23 commit 0 last mr release
(1 row)

omm=# create table accounts (name varchar2, amount int);
CREATE TABLE
omm=# insert into accounts values ('A',100),('B',100),('C',100),('D',99);
INSERT 0 4
omm=# delete from accounts where amount-99;
DELETE 3
omm=# select * from accounts;
name | amount
------+--------
D   |     99
(1 row)

不管是什么误操作,如果真的发生了,那么在MogDB 3.0中还有闪回查询可以用。

闪回查询及相关实现在MogDB 3.0中发生了一些变化。

  1. 只对存储引擎为ustore的表起作用,默认的astore已经不再支持闪回查询。
  2. 需要先手工设置undo_retention_time。该参数表示回滚段中旧版本数据的保留时间,等同于允许闪回查询的时间跨度。该参数默认是0,任何闪回查询都会遇到restore point not found报错。

创建一张ustore的accounts表。

MogDB=# create table accounts (name varchar2, amount int) with (storage_type=ustore);
CREATE TABLE

修改undo_retention_time参数,该参数单位是秒,86400表示是24小时。该参数允许最大值2147483647,相当于大约68年。当然你不会设置这么大,因为这会导致回滚段中保留过多旧数据。

MogDB=# alter system set undo_retention_time=86400;
ALTER SYSTEM SET

插入一些测试数据,就用前面提到的账户和金额。

MogDB=#  insert into accounts values ('A',100),('B',100),('C',100),('D',99);
INSERT 0 4

现在,因为某种误操作,你删除了所有金额不等于99的账户记录。

MogDB=# delete from accounts where amount<>99;
DELETE 3

MogDB=# select * from accounts;
name | amount
------+--------
D   |     99
(1 row)

当你发现这个失误的时候,可能是在1分钟以后,也可能是在1小时以后,这没关系,但是不要超过24小时(因为undo_retention_time设置了24小时),否则就找不回来了。

检查当前的时间戳,然后预估你执行误操作时候的时间戳,比如用当前时间戳减去5分钟,为了简便演示,我在发出删除命令之前,检查了系统的时间戳。

MogDB=# select sysdate;
      sysdate
---------------------
2022-09-02 13:19:24
(1 row)

发起闪回查询。

MogDB=# select * from accounts timecapsule TIMESTAMP to_timestamp('2022-09-02 13:19:24','YYYY-MM-DD HH24:MI:SS');
name | amount
------+--------
A   |   100
B   |   100
C   |   100
D   |     99
(4 rows)

真正的恢复步骤,可以是按照删除命令的条件,利用闪回查询将所有被误删除的记录创建为一张临时表,然后再从临时表中将所有记录插入回原表中。

MogDB=# create table tmp_accounts as select * from accounts timecapsule TIMESTAMP to_timestamp('2022-09-02 13:19:24','YYYY-MM-DD HH24:MI:SS') where amount<>99;
INSERT 0 3

MogDB=# select * from tmp_accounts;
name | amount
------+--------
A   |   100
B   |   100
C   |   100
(3 rows)

MogDB=# insert into accounts select * from tmp_accounts;
INSERT 0 3

MogDB=# select * from accounts;
name | amount
------+--------
D   |     99
A   |   100
B   |   100
C   |   100
(4 rows)

How to find the corresponding session in MogDB/openGauss from OS thread ID

诊断需求

当MogDB数据库由于某种原因占用了较大的系统负载,比如CPU占用接近100%,那么如何知道到底是数据库里的哪个会话或者哪些会话占用了资源?
在Oracle数据库中,这样的问题诊断,通常都会关联 vsession, vprocess, 以及操作系统top命令或者ps命令中查到的操作系统进程ID。
但是MogDB本身是线程模型,在操作系统上只能看到一个进程号,那么该如何定位问题?

因为MogDB使用的是线程模型,与PostgreSQL的进程模型不同,在操作系统级别如果用lsof命令查看网络端口的接入,虽然是会看到有多个用户会话接入,但是在PID列只会显示进程ID,无法对应到线程。

$ lsof -i 4 -a -p `pgrep -u omm3 mogdb`
COMMAND   PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
mogdb   12027 omm3    8u  IPv4 20313752      0t0  TCP *:biimenu (LISTEN)
mogdb   12027 omm3    9u  IPv4 20313753      0t0  TCP *:18001 (LISTEN)
mogdb   12027 omm3  325u  IPv4 28320946      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45206 (ESTABLISHED)
mogdb   12027 omm3  330u  IPv4 28316174      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45208 (ESTABLISHED)
mogdb   12027 omm3  336u  IPv4 28302815      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45210 (ESTABLISHED)
mogdb   12027 omm3  340u  IPv4 28323140      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45212 (ESTABLISHED)
mogdb   12027 omm3  360u  IPv4 28323141      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45214 (ESTABLISHED)
mogdb   12027 omm3  375u  IPv4 28305050      0t0  TCP mogdb-kernel-0004:biimenu->softbank060132034173.bbtec.net:45216 (ESTABLISHED)

如何获取线程ID

可以使用htop,打开htop界面以后,按F5进行进程树形显示,第一个PID是进程号,而树形结构下的每一行的PID都是该进程中对应的线程号。

也可以直接使用ps命令。-L参数表示显示线程,-o参数可以指定显示感兴趣的列。

# ps -Lp `pgrep -u omm3 mogdb` -o %cpu,tid,pid,ppid,cmd,comm
%CPU   TID   PID  PPID CMD                         COMMAND
 0.0 17847 17847     1 /opt/mogdb3/app/bin/mogdb - mogdb
 0.0 17848 17847     1 /opt/mogdb3/app/bin/mogdb - jemalloc_bg_thd
 0.0 17854 17847     1 /opt/mogdb3/app/bin/mogdb - mogdb
 0.0 17855 17847     1 /opt/mogdb3/app/bin/mogdb - syslogger
 0.0 17856 17847     1 /opt/mogdb3/app/bin/mogdb - reaper
 0.0 17857 17847     1 /opt/mogdb3/app/bin/mogdb - jemalloc_bg_thd
 0.0 17858 17847     1 /opt/mogdb3/app/bin/mogdb - jemalloc_bg_thd
 0.0 17860 17847     1 /opt/mogdb3/app/bin/mogdb - jemalloc_bg_thd
 0.0 17884 17847     1 /opt/mogdb3/app/bin/mogdb - checkpointer
 0.0 17885 17847     1 /opt/mogdb3/app/bin/mogdb - Spbgwriter
 0.1 17886 17847     1 /opt/mogdb3/app/bin/mogdb - pagewriter
 0.0 17887 17847     1 /opt/mogdb3/app/bin/mogdb - pagewriter
 0.0 17888 17847     1 /opt/mogdb3/app/bin/mogdb - pagewriter
 0.0 17889 17847     1 /opt/mogdb3/app/bin/mogdb - pagewriter
 0.0 17890 17847     1 /opt/mogdb3/app/bin/mogdb - pagewriter
 0.8 17891 17847     1 /opt/mogdb3/app/bin/mogdb - WALwriter
 0.0 17892 17847     1 /opt/mogdb3/app/bin/mogdb - WALwriteraux
 0.0 17893 17847     1 /opt/mogdb3/app/bin/mogdb - AVClauncher
 0.0 17894 17847     1 /opt/mogdb3/app/bin/mogdb - Jobscheduler
 0.0 17895 17847     1 /opt/mogdb3/app/bin/mogdb - asyncundolaunch
 0.0 17896 17847     1 /opt/mogdb3/app/bin/mogdb - globalstats
 0.0 17897 17847     1 /opt/mogdb3/app/bin/mogdb - applylauncher
 0.0 17898 17847     1 /opt/mogdb3/app/bin/mogdb - statscollector
 0.0 17899 17847     1 /opt/mogdb3/app/bin/mogdb - snapshotworker
 0.1 17900 17847     1 /opt/mogdb3/app/bin/mogdb - TrackStmtWorker
 0.0 17901 17847     1 /opt/mogdb3/app/bin/mogdb - 2pccleaner
 0.0 17902 17847     1 /opt/mogdb3/app/bin/mogdb - faultmonitor
 0.0 17904 17847     1 /opt/mogdb3/app/bin/mogdb - undorecycler
 0.0 18372 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18373 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18374 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18375 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18376 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18377 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18378 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18379 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18380 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18381 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18382 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18454 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 19475 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 19480 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 29529 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 30999 17847     1 /opt/mogdb3/app/bin/mogdb - worker

comm列中显示为woker的都是用户会话的数据库端后台进程,通常占用CPU较高的会是用户会话,因此可以用grep命令来过滤只显示用户会话。

#  ps -Lp `pgrep -u omm3 mogdb` -o %cpu,tid,pid,ppid,cmd,comm | grep -w worker
 0.0 18372 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18373 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18374 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18375 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18376 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18377 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18378 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18379 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18380 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18381 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18382 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 18454 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 19475 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 19480 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 29529 17847     1 /opt/mogdb3/app/bin/mogdb - worker
 0.0 30999 17847     1 /opt/mogdb3/app/bin/mogdb - worker

如何将操作系统线程ID跟数据库会话对应

假设在这台服务器上,线程ID=18372的线程占用了大量CPU。

在MogDB里查询pg_os_threads视图,可以获得该线程在数据库中对应的会话ID 。

MogDB=# select * from pg_os_threads where lwpid=18372;
 node_name |       pid       | lwpid | thread_name |         creation_time
-----------+-----------------+-------+-------------+-------------------------------
 dn_6001   | 140545137571584 | 18372 | dn_6001     | 2022-05-30 19:54:42.459129+08
(1 row)

pg_os_threads视图里记录了轻量级线程号和会话ID的关系,其中lwpid是操作系统线程ID,pid列是数据库会话ID。具体信息可以参考MogDB文档-PG_OS_THREADS
如果具备monadmin权限,也可以查询dbe_perf模式下的os_threads视图,信息是一样的。

找到数据库会话ID之后,就可以为所欲为了,比如可以查询dbe_perf.session_stat_activity视图来获取该会话的应用名,发起的客户端IP地址,还有该会话正在执行的SQL。

MogDB=# select application_name,client_addr,query from dbe_perf.session_stat_activity where pid=140545137571584;
 application_name | client_addr  |                          query
------------------+--------------+---------------------------------------------------------
 dn_6001          | 172.16.0.176 | SELECT cfg_value FROM bmsql_config  WHERE cfg_name = $1
(1 row)

也可以查询dbe_perf.thread_wait_status视图来获取会话的当前等待事件。BTW,实际上该视图中有lwtid字段,可以直接对应到线程ID。

MogDB=# select lwtid,wait_status,wait_event from dbe_perf.thread_wait_status where sessionid=140545137571584;
 lwtid | wait_status | wait_event
-------+-------------+------------
 18372 | wait cmd    | wait cmd
(1 row)

How to create a PowerShell alias to connect MogDB

MogDB是云和恩墨发布的基于开源数据库openGauss的企业级发行版。在连接串方面兼容标准的PostgreSQL连接方式,而pgcli是连接PostgreSQL的一个优秀客户端程序。本文描述如何在Windows系统的Powershell中设置alias,来简便地连接到MogDB数据库。

pgcli的安装不再赘述,可以参考pgcli网站中描述的安装方法,比较简单。

使用pgcli连接数据库,并且同时把密码也放在连接串中完成一条命令就直接登录数据库,例子如下:

 pgcli postgres://amjith:passw0rd@example.com:5432/app_db

其中每个部分的含义如下:

  • postgres://是标准的数据库类型提示符,不需要变更;
  • amjith是连接数据库的用户名,passw0rd是用户密码;
  • example.com是数据库所在的服务器hostname,可以直接使用IP地址来替换;
  • 5432是数据库监听的端口;
  • app_db是需要连接的数据库名称。

需要注意的一点是,如果在密码中存在“@”这样的特殊字符,那么需要把@改写成“%40”,比如密码如果是passw0rd@123,则命令行需要写成:

pgcli postgres://amjith:passw0rd%40123@example.com:5432/app_db

接下来,我们需要设置一个更简单的alias,比如我习惯使用p1,设置完毕以后,在命令行窗口键入p1以后回车,就可以直接连接到目标数据库。

如果是macOS,我们可以直接设置.zshrc文件;如果是Linux,可以设置.bash_profile。那么在Windows操作系统中,如果使用Powershell,该如何设置?

首先,要找到Powershell的配置文件路径,当安装完Powershell之后,进入Powershell命令行。

PS C:\Users\kamus> echo $profile
D:\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

如果没有该文件,则创建该文件,然后使用任何文本编辑器,在该文件中加入以下行。

Function pgcli_mogdb1 {pgcli --prompt "\u@\d> " postgres://amjith:passw0rd%40123@example.com:5432/app_db}
   Set-Alias -Name p1 -Value pgcli_mogdb1

因为Set-Alias命令的限制,一整条pgcli命令算是复杂命令,需要先写入到一个function中,然后再调用该function。

最后的效果如下:

PS C:\Users\kamus> p1
Server: PostgreSQL 9.2.4
Version: 3.1.0
Chat: https://gitter.im/dbcli/pgcli
Home: http://pgcli.com
mogdb@ocomp> select version();
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| version                                                                                                                                                           |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| PostgreSQL 9.2.4 (MogDB 2.0.0 build b75b585a) compiled at 2021-05-28 17:20:47 commit 0 last mr   on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
SELECT 1
Time: 0.072s
mogdb@ocomp>