Skip to content

hslightdb/LightDB-FAQ

Repository files navigation

LightDB(22.4之前版本 && 23.1之后版本) FAQ

1、如何选择LightDB安装包进行安装及确认数据库模式

LightDB下载页面:http://www.light-pg.com/downloadCate.html
LightDB-X 下载地址:http://www.light-pg.com/downloadList.html?key=lightDB_X
LightDB-A 下载地址:http://www.light-pg.com/downloadList.html?key=lightDB_A
LightDB EM 下载地址:http://www.light-pg.com/downloadList.html?key=lightDB_EM
选择对应的CPU架构和操作系统进行下载

1.1 如何确定操作系统版本呢?

我们以麒麟系统为例,如下

# nkvers
############## Kylin Linux Version #################
Release:
Kylin Linux Advanced Server release V10 (Tercel)

Kernel:
4.19.90-23.8.v2101.ky10.aarch64

Build:
Kylin Linux Advanced Server
release V10 (SP1) /(Tercel)-aarch64-Build20/20210518
#################################################

# lscpu
Architecture:                    aarch64
CPU op-mode(s):                  64-bit
Byte Order:                      Little Endian
CPU(s):                          96
On-line CPU(s) list:             0-95
Thread(s) per core:              1
Core(s) per socket:              48
Socket(s):                       2
NUMA node(s):                    4
Vendor ID:                       HiSilicon
Model:                           0
Model name:                      Kunpeng-920
Stepping:                        0x1
BogoMIPS:                        200.00
L1d cache:                       6 MiB
L1i cache:                       6 MiB
L2 cache:                        48 MiB
L3 cache:                        96 MiB
NUMA node0 CPU(s):               0-23
NUMA node1 CPU(s):               24-47
NUMA node2 CPU(s):               48-71
NUMA node3 CPU(s):               72-95
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Not affected
Vulnerability Spectre v1:        Mitigation; __user pointer sanitization
Vulnerability Spectre v2:        Not affected
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma dcpop 
                                 asimddp asimdfhm

可以看出操作系统为麒麟V10sp1,cpu架构为鲲鹏aarch64,则选择 LightDB1.0-x-V202302-00-000-ky10sp1-aarch64.zip 下载安装。 img.png 同样的客户端包需要下载包类型为"客户端"的软件包,如下所示:
img_8.png 关于客户端包的使用可以参考该链接:https://blog.csdn.net/yunmu666/article/details/130732807

1.2 使用安装手册进行安装

LightDB文档入口:http://www.light-pg.com/documents.html
上述链接中包含LightDB官方手册、安装文档、数据库迁移文档、JDBC参考手册、数据库参考手册等,建议详细阅读
LightDB-X安装文档:http://www.light-pg.com/docs/LightDB_Install_Manual/current/index.html
LightDB-A安装文档:http://www.light-pg.com/docs/LightDB-A-Install-Manual/current/index.html

1.3 确认LightDB数据库模式为Oracle还是MySQL

LightDB支持三种数据库模式, 分别是Oracle、MySQL、PostgreSQL, 我们可以登录到对应的业务数据库中通过下面命令确认:

-- 确保登录到业务数据库中,而不是默认的postgresql库或者lt_test库
-- 使用\l+查询实例中有哪些数据库

$ ltsql -U test -d test
ltsql (13.8-23.2)
Type "help" for help.
test@test=# \l+
                                                                         List of databases
         Name          |  Owner  | Encoding |   Collate   |    Ctype    |   Access privileges   |  Size   | Tablespace |                Description                 
-----------------------+---------+----------+-------------+-------------+-----------------------+---------+------------+--------------------------------------------
 lt_test               | lightdb | UTF8     | en_US.UTF-8 | en_US.UTF-8 |                       | 14 MB   | pg_default | 
 ltcluster             | lightdb | UTF8     | en_US.UTF-8 | en_US.UTF-8 |                       | 1070 MB | pg_default | 
 postgres              | lightdb | UTF8     | en_US.UTF-8 | en_US.UTF-8 |                       | 120 GB  | pg_default | default administrative connection database
 template0             | lightdb | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/lightdb           +| 8217 kB | pg_default | unmodifiable empty database
 template1             | lightdb | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/lightdb           +| 8217 kB | pg_default | default template for new databases

test@test=# show %compatible_type%;
                  name                  | setting |                                   description                                
   
----------------------------------------+---------+------------------------------------------------------------------------------
---
 lightdb_dblevel_syntax_compatible_type | Oracle  | Show syntax compatible type for current database.
 lightdb_syntax_compatible_type         | Oracle  | Default syntax compatible type when create database.  Support MySQL and Oracl
e.
(2 rows)
     
-- 如下表示test用户登录到postgres数据库下, test@postgres表示:用户@数据库
test@test=# \c postgres
You are now connected to database "postgres" as user "test".
test@postgres=# 
test@postgres=# show %compatible_type%;
                  name                  | setting |                                   description                                   
----------------------------------------+---------+---------------------------------------------------------------------------------
 lightdb_dblevel_syntax_compatible_type | off     | Show syntax compatible type for current database.
 lightdb_syntax_compatible_type         | Oracle  | Default syntax compatible type when create database.  Support MySQL and Oracle.
(2 rows)

创建数据库语句

test@test=# \h create database
Command:     CREATE DATABASE
Description: create a new database
Syntax:
CREATE DATABASE name
    [ [ WITH ] [ OWNER [=] user_name ]
           [ TEMPLATE [=] template ]
           [ ENCODING [=] encoding ]
           [ LOCALE [=] locale ]
           [ LC_COLLATE [=] lc_collate ]
           [ LC_CTYPE [=] lc_ctype ]
           [ TABLESPACE [=] tablespace_name ]
           [ ALLOW_CONNECTIONS [=] allowconn ]
           [ CONNECTION LIMIT [=] connlimit ]
           [ IS_TEMPLATE [=] istemplate ] ]
           [ LIGHTDB_SYNTAX_COMPATIBLE_TYPE [=] compa_type ] ]

说明:

  • lightdb_syntax_compatible_type表示安装数据库软件时的默认级别
  • lightdb_dblevel_syntax_compatible_type表示数据库级别的模式,Oracle即为Oracle模式、Mysql为MySQL模式、off表示为默认的PostgreSQL模式,其中postgres和lt_test默认都为off的PostgreSQL模式

2、LightDB如何进行逻辑备份、恢复

2.1 常用备份和恢复命令

备份命令

PGPASSWORD=hundsun lt_dump -Usubacc1 -h10.19.36.28 -p5432 -d subacc1 -n subacc1 -n subacc2 -F d -j 10 --if-exists -c -f subacc1 -v > exp.log 2>&1 & 

说明:

  • PGPASSWORD=密码
  • lt_dump 逻辑备份命令
  • -U 指定导出用户名
  • -h 指定导出实例IP
  • -p 指定导出实例端口
  • -d 指定导出数据库名
  • -n 导出数据库的schema名字,可以指定多个schema, 如:-n subacc1 -n subacc2
  • -j 10 表示使用10个并行进行导出
  • -F d 其中-F表示导出文件格式, d表示为目录格式
  • --if-exists -c 如果存在就删除重新创建
  • -f 导出文件名
  • -v 表示输出日志详情
    习惯于MySQL的mysqldump的同学可能会有疑问,一般的密码提示都是放在备份命令中,而PGPASSWORD为什么要放前面,其实这个PG/LightDB的规范,他其实也是shell中的变量
$ export PGPASSWORD=xxx
$ lt_dump -Usubacc1 -h10.19.36.28 -p5432 -d subacc1 -n subacc1 -F d -j 10 --if-exists -c -f subacc1 -v > exp.log 2>&1 & 

常用恢复命令

PGPASSWORD=hundsun lt_restore subacc1 -U lightdb -h 10.19.36.28 -p 5432 -d subacc1 --if-exists -c -v > imp.log 2>&1 & 

说明:

  • lt_restore
  • subacc1 表示使用lt_dump导出的那个目录名称, 要紧跟lt_restore命令后面 其余参数与lt_dump导出说明含义类似

2.2 并行的进行备份和恢复

PGPASSWORD=hundsun lt_dump -Fd -Ulightdb -h 10.19.36.28 -p 5432 -d fund60 -j8 -f fund60 -c --if-exists -v 

PGPASSWORD=hundsun lt_restore fund60 -U lightdb -h 10.19.36.28 -p 5432 -n fund60acco1 -n fund60pub -j8 -d fund60 --section=pre-data --section=data --if-exists -c -v
PGPASSWORD=hundsun lt_restore fund60 -U lightdb -h 10.19.36.28 -p 5432 -n fund60acco1 -n fund60pub -d fund60 --section=post-data --if-exists -c -v

2.3 导出和导入insert SQL文本

备份命令

lt_dump -U test -d test -n test -p 5432 -h 10.20.30.211 --inserts -f test.sql -v

恢复命令

ltsql -U test -d test -n test -p 5432 -h 10.20.30.210 -f test.sql

说明:优先考虑逻辑备份和恢复的效率, 优先使用2.2方式,因为会使用并行和压缩机制, 如果想导出文本方便获取SQL、表结构定义可以使用2.3方式

3、如何进行LightDB客户端部署,LightDB是否有windows版客户端?

1、安装包上传到客户端服务器

解压并且给予相应的权限,应用服务器系统用户我们以ta6为例

[ta6@client ~]$ cd /home/ta6/lightdb_client/lightdb-x-13.3-22.2-5950-kylinV10sp1.x86_64/lightdb-x/13.3-22.2/bin/
[ta6@client bin]$ pwd
/home/ta6/lightdb_client/lightdb-x-13.3-22.2-5950-kylinV10sp1.x86_64/lightdb-x/13.3-22.2/bin

2、配置环境变量

[ta6@client bin]$ cat ~/.bashrc 
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions

export PGHOME=/home/ta6/lightdb_client/lightdb-x-13.3-22.2-5950-kylinV10sp1.x86_64/lightdb-x/13.3-22.2
export PATH=${PGHOME}/bin:${PGHOME}/tools/iftop/bin:${PGHOME}/tools/iotop/bin:${PGHOME}/tools/linux-ftools/bin:${PGHOME}/tools/vmtouch/bin:${PATH}
export LD_LIBRARY_PATH=${PGHOME}/lib:${PGHOME}/lib/ltext:${LD_LIBRARY_PATH}

3、执行. ~/.bashrc 使环境变量生效

4、验证

如果执行ltsql、lt_dump等命令成功返回结果,说明客户端部署正常,如果执行命令时显示缺少系统依赖包等问题,举例如下

$ ltsql
ltsql: error while loading shared libraries: libreadline.so.8: canot open shared object file

上述错误说明系统缺少readline包,可以yum进行安装,如果配置yum环境受限,可以进入安装包的system-lib下使用rpm进行安装

# cd lightdb-x-13.3-22.2-5950-kylinV10sp1.x86_64/system-lib
# rpm -ivh readline-8.0.3.ky10.x86_64.rpm

LightDB是否有Windows版本客户端?

LightDB数据库中自带有Linux版客户端ltsql,如果想使用Windows版本对应的客户端,且不使用LightDB的匿名块功能时,可以使用PostgreSQL的psql客户端Windows版本,LightDB数据库的ltsql客户端针对PostgreSQL的psql客户端完全兼容,故可以直接通过PostgreSQL的psql连接操作LightDB数据库

4、LightDB更改列属性语法

从LightDB 22.3开始modify column语法完全兼容Oracle
在LightDB22.2之前,习惯于Oracle语法的同学,习惯用下面SQL执行更改列名和默认值等

SQL> desc emp;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 EMPNO                                     NOT NULL NUMBER(4)
 ENAME                                              VARCHAR2(10)
 JOB                                                VARCHAR2(9)
 MGR                                                NUMBER(4)
 HIREDATE                                           DATE
 SAL                                                NUMBER(7,2)
 COMM                                               NUMBER(7,2)
 DEPTNO                                             NUMBER(2)
 DNAME                                              VARCHAR2(100)
SQL> 
SQL> alter table emp modify ename varchar2(20) default ' ';
Table altered.

LightDB用法

lightdb@postgres=# alter table emp alter column ename type varchar2(20);
ALTER TABLE
lightdb@postgres=# alter table emp alter column ename set default ' ';
ALTER TABLE
lightdb@postgres=# \d emp
                       Table "public.emp"
  Column  |     Type      | Collation | Nullable |    Default    
----------+---------------+-----------+----------+---------------
 empno    | numeric(4,0)  |           | not null | 
 ename    | varchar2(20)  |           |          | ' '::varchar2
 job      | varchar2(9)   |           |          | 
 mgr      | numeric(4,0)  |           |          | 
 hiredate | date          |           |          | 
 sal      | numeric(7,2)  |           |          | 
 comm     | numeric(7,2)  |           |          | 
 deptno   | numeric(2,0)  |           |          | 
 dname    | varchar2(100) |           |          | 
Indexes:
    "pk_emp" PRIMARY KEY, btree (empno)

\h alter table 

5、LightDB的递归语法

我们知道Oracle的递归语句为start with connect by语法,同样在LightDB 23.2及以后版本, LightDB兼容Oracle 递归 Oracle:

SELECT
	DISTINCT ID,
	PARENT_MODULE_CODE,
	MODULE_CODE,
	MODULE_NAME,
	LEAF_MARK,
	NODE_EXPAND,
	RAR_NAME_FORMAT,
	RAR_SUFFIX_FORMAT,
	REPORT_FILE_NAME_FORMAT,
	REPORT_FILE_SUFFIX_FORMAT,
	EXPORT_FILE_PATH,
	REPORT_SEND_TYPE,
	FILING_TYPE,
	FEED_BACK_DOC_PATH,
	FEED_BACK_DOC_NAME_FORMAT,
	FEED_BACK_DOC_SUFFIX_FORMAT,
	BUSINESS_REPORT_SQL,
	CREATE_TIME,
	UPDATE_TIME,
	CREATOR_NO,
	UPDATOR_NO,
	STATUS,
	REPORT_FILE_CODE,
	REPORT_RAR_CODE,
	GEN_REPORT_DATA_TYPE,
	GEN_REPORT_DATA_EXP,
	GEN_BDATA_DATASOURCE_ID,
	ENV_ID
FROM URP_REPORT_MODULE t
WHERE env_id = '001'
START WITH status = 1
CONNECT BY PRIOR t.parent_module_code = t.module_code
ORDER BY t.module_code ASC, t.module_name ASC;

LightDB 23.2 之前建议使用 with recursive 进行改写, 参考示例如下:

with recursive cte as (
select
	ID,
	PARENT_MODULE_CODE,
	MODULE_CODE,
	MODULE_NAME,
	LEAF_MARK,
	NODE_EXPAND,
	RAR_NAME_FORMAT,
	RAR_SUFFIX_FORMAT,
	REPORT_FILE_NAME_FORMAT,
	REPORT_FILE_SUFFIX_FORMAT,
	EXPORT_FILE_PATH,
	REPORT_SEND_TYPE,
	FILING_TYPE,
	FEED_BACK_DOC_PATH,
	FEED_BACK_DOC_NAME_FORMAT,
	FEED_BACK_DOC_SUFFIX_FORMAT,
	BUSINESS_REPORT_SQL,
	CREATE_TIME,
	UPDATE_TIME,
	CREATOR_NO,
	UPDATOR_NO,
	STATUS,
	REPORT_FILE_CODE,
	REPORT_RAR_CODE,
	GEN_REPORT_DATA_TYPE,
	GEN_REPORT_DATA_EXP,
	GEN_BDATA_DATASOURCE_ID,
	ENV_ID
from
	URP_REPORT_MODULE
where
	status = 1
union all
select
	d.ID,
	d.PARENT_MODULE_CODE,
	d.MODULE_CODE,
	d.MODULE_NAME,
	d.LEAF_MARK,
	d.NODE_EXPAND,
	d.RAR_NAME_FORMAT,
	d.RAR_SUFFIX_FORMAT,
	d.REPORT_FILE_NAME_FORMAT,
	d.REPORT_FILE_SUFFIX_FORMAT,
	d.EXPORT_FILE_PATH,
	d.REPORT_SEND_TYPE,
	d.FILING_TYPE,
	d.FEED_BACK_DOC_PATH,
	d.FEED_BACK_DOC_NAME_FORMAT,
	d.FEED_BACK_DOC_SUFFIX_FORMAT,
	d.BUSINESS_REPORT_SQL,
	d.CREATE_TIME,
	d.UPDATE_TIME,
	d.CREATOR_NO,
	d.UPDATOR_NO,
	d.STATUS,
	d.REPORT_FILE_CODE,
	d.REPORT_RAR_CODE,
	d.GEN_REPORT_DATA_TYPE,
	d.GEN_REPORT_DATA_EXP,
	d.GEN_BDATA_DATASOURCE_ID,
	d.ENV_ID
from
	URP_REPORT_MODULE d
join cte on
	cte.parent_module_code = d.module_code )
select
	distinct ID,
	PARENT_MODULE_CODE,
	MODULE_CODE,
	MODULE_NAME,
	LEAF_MARK,
	NODE_EXPAND,
	RAR_NAME_FORMAT,
	RAR_SUFFIX_FORMAT,
	REPORT_FILE_NAME_FORMAT,
	REPORT_FILE_SUFFIX_FORMAT,
	EXPORT_FILE_PATH,
	REPORT_SEND_TYPE,
	FILING_TYPE,
	FEED_BACK_DOC_PATH,
	FEED_BACK_DOC_NAME_FORMAT,
	FEED_BACK_DOC_SUFFIX_FORMAT,
	BUSINESS_REPORT_SQL,
	CREATE_TIME,
	UPDATE_TIME,
	CREATOR_NO,
	UPDATOR_NO,
	STATUS,
	REPORT_FILE_CODE,
	REPORT_RAR_CODE,
	GEN_REPORT_DATA_TYPE,
	GEN_REPORT_DATA_EXP,
	GEN_BDATA_DATASOURCE_ID,
	ENV_ID
from
	cte
order by
	cte.module_code asc,
	cte.module_name asc;

6、如何确定LightDB当前连接是否已满

查询SQL语句如下:

SELECT NAME, setting::number as cnt FROM pg_settings WHERE NAME = 'max_connections'
union all
select state ,count(*)  as cnt from pg_stat_activity group by state;
      name       | cnt  
-----------------+------
 max_connections | 2000
                 |    5
 active          |    2
 idle            |  709
(4 rows)

说明:max_connections表示当前数据库最大连接数为2000

如果确定连接已满,接下来怎么排查?

如果ltsql没有指定-h host/ip,也没有配置LTHOST/PGHOST环境变量, 那么默认会走unix domain socket, 在这种场景tcp_keepalives相关选项不起作用, 查询时显示0, 示例如下:

$ ltsql -p 5432
ltsql (13.8-22.3)
Type "help" for help.

test=# show tcp_keepalives%;
          name           | setting |                 description                  
-------------------------+---------+----------------------------------------------
 tcp_keepalives_count    | 0       | Maximum number of TCP keepalive retransmits.
 tcp_keepalives_idle     | 0       | Time between issuing TCP keepalives.
 tcp_keepalives_interval | 0       | Time between TCP keepalive retransmits.
(3 rows)

如果指定IP,则可显示lightdb.conf中配置的参数值:

$ ltsql -p 5432 -h 127.0.0.1
ltsql (13.8-22.3)
Type "help" for help.

test=# show tcp_keepalives%;
          name           | setting |                 description                  
-------------------------+---------+----------------------------------------------
 tcp_keepalives_count    | 5       | Maximum number of TCP keepalive retransmits.
 tcp_keepalives_idle     | 300     | Time between issuing TCP keepalives.
 tcp_keepalives_interval | 30      | Time between TCP keepalive retransmits.
(3 rows)

7、如何配置LightDB集成开发环境

Oracle一般习惯使用PL/SQL developer做为集成开发环境,同样LightDB为了使用自己的存储过程等特性,推荐使用dbeaver集成环境并且需要配置LightDB驱动。
下载最新LightDB驱动,选择最新日期进行下载,驱动下载地址:https://mvnrepository.com/artifact/io.github.hslightdb/ltjdbc
dbeaver下载地址:https://dbeaver.io/
下载成功安装后,找到数据库->驱动管理器->新建
img_3.png img_4.png
点击"新建"后填入如下内容,同时选择"库"选项,添加LightDB驱动
下面是配置模版,需要完全按照模版内容填写
org.postgresql.Driver
jdbc:postgresql://{host}[:{port}]/[{database}]

img_5.png
上传2个jar文件
img_13.png
上述操作完成后,点击"确定"
img_6.png
点击"关闭"之后,点击左上角加号,选择LightDB驱动程序
img_7.png

填写数据库IP、端口、用户名、密码等信息,测试连接登录即可
img_9.png
最后更改LightDB兼容属性,小写oracle img_10.png

8、如何实现LightDB访问Oracle表

1、安装插件

LightDB默认集成了oracle_fdw插件

create extension oracle_fdw;

2、安装Oracle客户端

oracle轻量客户端可直接从oracle官网https://www.oracle.com/database/technologies/instant-client/downloads.html下载。

instantclient-basic-linux.x64-21.6.0.0.0dbru.zip
instantclient-sdk-linux.x64-21.6.0.0.0dbru.zip
instantclient-sqlplus-linux.x64-21.6.0.0.0dbru.zip

解压到当前目录

[lightdb@node1 ~]$ pwd
/home/lightdb
[lightdb@node1 ~]$ unzip instantclient-basic-linux.x64-21.6.0.0.0dbru.zip
[lightdb@node1 ~]$ unzip instantclient-sdk-linux.x64-21.6.0.0.0dbru.zip
[lightdb@node1 ~]$ unzip instantclient-sqlplus-linux.x64-21.6.0.0.0dbru.zip
[lightdb@node1 ~]$ ls -ltr | grep 21.6
-rw-r--r--  1 lightdb lightdb  78665919 Jul  1 11:10 instantclient-basic-linux.x64-21.6.0.0.0dbru.zip
-rw-r--r--  1 lightdb lightdb   1001535 Jul  1 11:48 instantclient-sdk-linux.x64-21.6.0.0.0dbru.zip
-rw-r--r--  1 lightdb lightdb    936841 Jul  1 13:12 instantclient-sqlplus-linux.x64-21.6.0.0.0dbru.zip
drwxrwxr-x  4 lightdb lightdb      4096 Jul  1 13:16 instantclient_21_6

配置环境变量

cat ~/.bash_profile
export PATH
export EDITOR=vi 
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
export ORACLE_BASE=/home/lightdb/instantclient_21_6
export ORACLE_HOME=/home/lightdb/instantclient_21_6
export ORACLE_SID=
export PATH=$ORACLE_HOME:$ORACLE_HOME/OPatch:$GGATE:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME:/usr/lib:$GGATE:$LD_LIBRARY_PATH
export TNS_ADMIN=$ORACLE_HOME/network/admin

3、创建foreign 表

create server oradb foreign data wrapper oracle_fdw options (dbserver '//10.0.4.4:1521/orcl1');
--对应删除命令
postgres=# DROP SERVER IF EXISTS oradb CASCADE;
NOTICE:  drop cascades to foreign table haha
DROP SERVER

create user mapping for USER server oradb options (user 'HR', password 'HR');
-- 对应的删除命令
postgres=# drop user mapping if exists for USER SERVER oradb;
DROP USER MAPPING
GRANT USAGE ON FOREIGN DATA WRAPPER oracle_fdw TO CURRENT_USER;
GRANT USAGE ON FOREIGN SERVER oradb TO CURRENT_USER;
create foreign table haha ( id int)
SERVER oradb OPTIONS (schema 'hr', table 'haha');
-- 创建对应结构的表,在PostgreSQL端要指明表结构,对应字段为PostgreSQL的字段类型
drop foreign table JOBS;
create foreign table JOBS 
(JOB_ID VARCHAR(10) NOT NULL,
 JOB_TITLE  VARCHAR(35) NOT NULL,
 MIN_SALARY NUMBER(6),
 MAX_SALARY NUMBER(6)) SERVER oradb OPTIONS (schema 'HR', table 'JOBS');


postgres=# select * from haha;
ERROR:  Oracle table "hr"."haha" for foreign table "haha" does not exist or does not allow read access
DETAIL:  ORA-00942: table or view does not exist
HINT:  Oracle table names are case sensitive (normally all uppercase).

如上错误是因为Oracle表默认存储底层为大写,在PostgreSQL端如果查询小写表名,遍报不存在错误,按照如下重建即可,表明haha要指定为大写 HAHA

postgres=# drop foreign table haha;
DROP FOREIGN TABLE
postgres=# create foreign table haha 
postgres-#    ( id int)
postgres-# SERVER oradb OPTIONS (schema 'HR', table 'HAHA');
CREATE FOREIGN TABLE
postgres=# select * from haha;
 id 
----
  1
(1 row)
postgres=# \d
                             List of relations
 Schema |                  Name                  |     Type      |  Owner  
--------+----------------------------------------+---------------+---------
 public | baselines                              | table         | lightdb
 public | baselines_bl_id_seq                    | sequence      | lightdb
 public | bl_samples                             | table         | lightdb
 public | dual                                   | view          | lightdb
 public | funcs_list                             | table         | lightdb
 public | haha                                   | foreign table | lightdb

可以看到haha表类型为foreign table,指向了oradb的hr用户下的haha表

postgres-# \d haha
                   Foreign table "public.haha"
 Column |  Type   | Collation | Nullable | Default | FDW options 
--------+---------+-----------+----------+---------+-------------
 id     | integer |           |          |         | 
Server: oradb
FDW options: (schema 'HR', "table" 'HAHA')

查看fdw server

postgres=# select * from pg_foreign_server;
  oid   | srvname | srvowner | srvfdw | srvtype | srvversion |       srvacl        |            srvoptions            
--------+---------+----------+--------+---------+------------+---------------------+----------------------------------
 485122 | oradb   |       10 | 485121 |         |            | {lightdb=U/lightdb} | {dbserver=//10.0.4.4:1521/orcl1}
(1 row)

外部表和用户映射关系

postgres=# select * from pg_foreign_table;
 ftrelid | ftserver |       ftoptions        
---------+----------+------------------------
  485414 |   485122 | {schema=HR,table=HAHA}
(1 row)

postgres=# select * from pg_user_mapping;
  oid   | umuser | umserver |       umoptions       
--------+--------+----------+-----------------------
 485123 |     10 |   485122 | {user=hr,password=hr}
(1 row)

postgres=# select * from pg_foreign_data_wrapper;
  oid   |     fdwname     | fdwowner | fdwhandler | fdwvalidator |       fdwacl        | fdwoptions 
--------+-----------------+----------+------------+--------------+---------------------+------------
  15199 | dblink_fdw      |       10 |          0 |        15198 |                     | 
  17299 | timescaledb_fdw |       10 |      17297 |        17298 |                     | 
 485121 | oracle_fdw      |       10 |     485116 |       485117 | {lightdb=U/lightdb} | 
(3 rows)

9、如何定位LightDB数据库中锁阻塞链情况

执行下面SQL即可情况锁阻塞链情况:

WITH RECURSIVE
  lock_composite(requested, current) AS (VALUES
    ('AccessShareLock'::text, 'AccessExclusiveLock'::text),
    ('RowShareLock'::text, 'ExclusiveLock'::text),
    ('RowShareLock'::text, 'AccessExclusiveLock'::text),
    ('RowExclusiveLock'::text, 'ShareLock'::text),
    ('RowExclusiveLock'::text, 'ShareRowExclusiveLock'::text),
    ('RowExclusiveLock'::text, 'ExclusiveLock'::text),
    ('RowExclusiveLock'::text, 'AccessExclusiveLock'::text),
    ('ShareUpdateExclusiveLock'::text, 'ShareUpdateExclusiveLock'::text),
    ('ShareUpdateExclusiveLock'::text, 'ShareLock'::text),
    ('ShareUpdateExclusiveLock'::text, 'ShareRowExclusiveLock'::text),
    ('ShareUpdateExclusiveLock'::text, 'ExclusiveLock'::text),
    ('ShareUpdateExclusiveLock'::text, 'AccessExclusiveLock'::text),
    ('ShareLock'::text, 'RowExclusiveLock'::text),
    ('ShareLock'::text, 'ShareUpdateExclusiveLock'::text),
    ('ShareLock'::text, 'ShareRowExclusiveLock'::text),
    ('ShareLock'::text, 'ExclusiveLock'::text),
    ('ShareLock'::text, 'AccessExclusiveLock'::text),
    ('ShareRowExclusiveLock'::text, 'RowExclusiveLock'::text),
    ('ShareRowExclusiveLock'::text, 'ShareUpdateExclusiveLock'::text),
    ('ShareRowExclusiveLock'::text, 'ShareLock'::text),
    ('ShareRowExclusiveLock'::text, 'ShareRowExclusiveLock'::text),
    ('ShareRowExclusiveLock'::text, 'ExclusiveLock'::text),
    ('ShareRowExclusiveLock'::text, 'AccessExclusiveLock'::text),
    ('ExclusiveLock'::text, 'RowShareLock'::text),
    ('ExclusiveLock'::text, 'RowExclusiveLock'::text),
    ('ExclusiveLock'::text, 'ShareUpdateExclusiveLock'::text),
    ('ExclusiveLock'::text, 'ShareLock'::text),
    ('ExclusiveLock'::text, 'ShareRowExclusiveLock'::text),
    ('ExclusiveLock'::text, 'ExclusiveLock'::text),
    ('ExclusiveLock'::text, 'AccessExclusiveLock'::text),
    ('AccessExclusiveLock'::text, 'AccessShareLock'::text),
    ('AccessExclusiveLock'::text, 'RowShareLock'::text),
    ('AccessExclusiveLock'::text, 'RowExclusiveLock'::text),
    ('AccessExclusiveLock'::text, 'ShareUpdateExclusiveLock'::text),
    ('AccessExclusiveLock'::text, 'ShareLock'::text),
    ('AccessExclusiveLock'::text, 'ShareRowExclusiveLock'::text),
    ('AccessExclusiveLock'::text, 'ExclusiveLock'::text),
    ('AccessExclusiveLock'::text, 'AccessExclusiveLock'::text)
  )
, lock AS (
  SELECT pid,
     virtualtransaction,
     granted,
     mode,
    (locktype,
     CASE locktype
       WHEN 'relation'      THEN concat_ws(';', 'db:'||datname, 'rel:'||relation::regclass::text)
       WHEN 'extend'        THEN concat_ws(';', 'db:'||datname, 'rel:'||relation::regclass::text)
       WHEN 'page'          THEN concat_ws(';', 'db:'||datname, 'rel:'||relation::regclass::text, 'page#'||page::text)
       WHEN 'tuple'         THEN concat_ws(';', 'db:'||datname, 'rel:'||relation::regclass::text, 'page#'||page::text, 'tuple#'||tuple::text)
       WHEN 'transactionid' THEN transactionid::text
       WHEN 'virtualxid'    THEN virtualxid::text
       WHEN 'object'        THEN concat_ws(';', 'class:'||classid::regclass::text, 'objid:'||objid, 'col#'||objsubid)
       ELSE concat('db:'||datname)
     END::text) AS target
  FROM pg_catalog.pg_locks
  LEFT JOIN pg_catalog.pg_database ON (pg_database.oid = pg_locks.database)
  )
, waiting_lock AS (
  SELECT
    blocker.pid                         AS blocker_pid,
    blocked.pid                         AS pid,
    concat(blocked.mode,blocked.target) AS lock_target
  FROM lock blocker
  JOIN lock blocked
    ON ( NOT blocked.granted
     AND blocker.granted
     AND blocked.pid != blocker.pid
     AND blocked.target IS NOT DISTINCT FROM blocker.target)
  JOIN lock_composite c ON (c.requested = blocked.mode AND c.current = blocker.mode)
  )
, acquired_lock AS (
  WITH waiting AS (
    SELECT lock_target, count(lock_target) AS wait_count FROM waiting_lock GROUP BY lock_target
  )
  SELECT
    pid,
    array_agg(concat(mode,target,' + '||wait_count) ORDER BY wait_count DESC NULLS LAST) AS locks_acquired
  FROM lock
    LEFT JOIN waiting ON waiting.lock_target = concat(mode,target)
  WHERE granted
  GROUP BY pid
  )
, blocking_lock AS (
  SELECT
    ARRAY[date_part('epoch', query_start)::int, pid] AS seq,
     0::int AS "depth",
    -1::int AS blocker_pid,
    pid,
    concat('Connect: ',usename,' ',datname,' ',coalesce(host(client_addr)||':'||client_port, 'local')
      , E'\nSQL: ',replace(substr(coalesce(query,'N/A'), 1, 60), E'\n', ' ')
      , E'\nAcquired:\n  '
      , array_to_string(locks_acquired[1:5] ||
                        CASE WHEN array_upper(locks_acquired,1) > 5
                             THEN '... '||(array_upper(locks_acquired,1) - 5)::text||' more ...'
                        END,
                        E'\n  ')
    ) AS lock_info,
    concat(to_char(query_start, CASE WHEN age(query_start) > '24h' THEN 'Day DD Mon' ELSE 'HH24:MI:SS' END),E' started\n'
          ,CASE WHEN wait_event IS NOT NULL THEN 'waiting' ELSE state END,E'\n'
          ,date_trunc('second',age(now(),query_start)),' ago'
    ) AS lock_state
  FROM acquired_lock blocker
  LEFT JOIN pg_stat_activity act USING (pid)
  WHERE EXISTS
         (SELECT 'x' FROM waiting_lock blocked WHERE blocked.blocker_pid = blocker.pid)
    AND NOT EXISTS
         (SELECT 'x' FROM waiting_lock blocked WHERE blocked.pid = blocker.pid)
UNION ALL
  SELECT
    blocker.seq || blocked.pid,
    blocker.depth + 1,
    blocker.pid,
    blocked.pid,
    concat('Connect: ',usename,' ',datname,' ',coalesce(host(client_addr)||':'||client_port, 'local')
      , E'\nSQL: ',replace(substr(coalesce(query,'N/A'), 1, 60), E'\n', ' ')
      , E'\nWaiting: ',blocked.lock_target
      , CASE WHEN locks_acquired IS NOT NULL
             THEN E'\nAcquired:\n  ' ||
                  array_to_string(locks_acquired[1:5] ||
                                  CASE WHEN array_upper(locks_acquired,1) > 5
                                       THEN '... '||(array_upper(locks_acquired,1) - 5)::text||' more ...'
                                  END,
                                  E'\n  ')
        END
    ) AS lock_info,
    concat(to_char(query_start, CASE WHEN age(query_start) > '24h' THEN 'Day DD Mon' ELSE 'HH24:MI:SS' END),E' started\n'
          ,CASE WHEN wait_event IS NOT NULL THEN 'waiting' ELSE state END,E'\n'
          ,date_trunc('second',age(now(),query_start)),' ago'
    ) AS lock_state
  FROM blocking_lock blocker
  JOIN waiting_lock blocked
    ON (blocked.blocker_pid = blocker.pid)
  LEFT JOIN pg_stat_activity act ON (act.pid = blocked.pid)
  LEFT JOIN acquired_lock acq ON (acq.pid = blocked.pid)
  WHERE blocker.depth < 5
  )
SELECT concat(lpad('=> ', 4*depth, ' '),pid::text) AS "PID", lock_info AS Lock_Info, lock_state AS State
FROM blocking_lock ORDER BY seq;

10、如果用户无法在自己的数据库中创建和删除schema怎么办

1、第一种情况一个数据库对应一个用户和对应schema

lightdb@postgres=# create user hundsun password 'hundsun';
CREATE ROLE
lightdb@postgres=# create database hundsun;
CREATE DATABASE
lightdb@postgres=# \c hundsun hundsun
You are now connected to database "hundsun" as user "hundsun".
hundsun1@hundsun1=> create schema hundsun;
ERROR:  permission denied for database hundsun

需要给用户赋予all privileges权限

$ ltsql -p 5435
ltsql (13.3-22.2)
Type "help" for help.

lightdb@postgres=# alter database hundsun owner to hundsun;
ALTER DATABASE
lightdb@postgres=# \c hundsun hundsun
You are now connected to database "hundsun" as user "hundsun".
hundsun@hundsun=> create schema hundsun;
CREATE SCHEMA

2、第二种情况一个数据库对应多个用户和多个schema

我们以TA6为例子

create user fund60acco1 password 'fund60acco1';
create user fund60acco2 password 'fund60acco2';
create user fund60pub password 'fund60pub';
create user fund60query password 'fund60query';
create user fund60trans1 password 'fund60trans1';
create user fund60trans2 password 'fund60trans2';
create database fund60;
grant all privileges on database fund60 to fund60trans1;
grant all privileges on database fund60 to fund60trans2;
grant all privileges on database fund60 to fund60acco1;
grant all privileges on database fund60 to fund60acco2;
grant all privileges on database fund60 to fund60pub;
grant all privileges on database fund60 to fund60query;

举例:使用fund60query用户登录到fund60数据库下创建同名schema

lightdb@postgres=# \c fund60 fund60query 
Password for user fund60query: 
You are now connected to database "fund60" as user "fund60query".
fund60query@fund60=> create schema fund60query;
CREATE SCHEMA

11、LightDB标准的创建用户语句是怎样的

我们以TA6为例子

$ ltsql
ltsql (13.3-22.2)
Type "help" for help.

lightdb@postgres=# create user fund60acco1 password 'fund60acco1';
CREATE ROLE
lightdb@postgres=# create user fund60acco2 password 'fund60acco2';
CREATE ROLE
lightdb@postgres=# create user fund60pub password 'fund60pub';
CREATE ROLE
lightdb@postgres=# create user fund60query password 'fund60query';
CREATE ROLE
lightdb@postgres=# create user fund60trans1 password 'fund60trans1';
CREATE ROLE
lightdb@postgres=# create user fund60trans2 password 'fund60trans2';
CREATE ROLE
lightdb@postgres=# create database fund60;
CREATE DATABASE
lightdb@postgres=# grant all privileges on database fund60 to fund60trans1;
GRANT
lightdb@postgres=# grant all privileges on database fund60 to fund60trans2;
GRANT
lightdb@postgres=# grant all privileges on database fund60 to fund60acco1;
GRANT
lightdb@postgres=# grant all privileges on database fund60 to fund60acco2;
GRANT
lightdb@postgres=# grant all privileges on database fund60 to fund60pub;
GRANT
lightdb@postgres=# grant all privileges on database fund60 to fund60query;
GRANT

再分别登录到自己到库中创建和用户同名到schema,下面只举了2个例子

lightdb@postgres=# \c fund60 fund60query 
Password for user fund60query: 
You are now connected to database "fund60" as user "fund60query".
fund60query@fund60=> create schema fund60query;
CREATE SCHEMA
fund60query@fund60=> \c fund60 fund60pub
Password for user fund60pub: 
You are now connected to database "fund60" as user "fund60pub".
fund60pub@fund60=> create schema fund60pub;
CREATE SCHEMA

12、如何下载和使用LightDB JDBC驱动

官方文档参考: http://www.light-pg.com/docs/LTJDBC/current/index.html
maven 地址,选择最新版进行下载 https://mvnrepository.com/artifact/io.github.hslightdb/ltjdbc

<!-- https://mvnrepository.com/artifact/io.github.hslightdb/ltjdbc -->
<dependency>
    <groupId>io.github.hslightdb</groupId>
    <artifactId>ltjdbc</artifactId>
    <version>42.2.25-23.2.0.1</version>
</dependency>

13、选择图形化安装LightDB 无法启动安装界面怎么办

GUI安装界面弹不出来,一般来说有两种原因:

  • 首先,缺人Linux系统是否已安装GUI程序所需的依赖包
yum install -y libXtst
yum install -y xterm
yum install -y xorg-x11-xauth
  • 其次,Linux系统未正确设置DISPLAY环境变量,或者Windows未正确运行Xmanager - Passive

如果无法满足上述条件,可以使用命令行安装模式,LightDB支持命令行安装模式,且与GUI安装相比仅在安装向导上有所差异,其余并无不同。

14、查看LightDB安装目录、实例目录、归档目录

数据库安装完成后,环境变量会写到~/.bashrc中,默认情况下数据库相关位置如下:

ls $LTHOME          # 查看安装目录
ls $LTDATA          # 查看实例目录
ls $LTHOME/archive  # 查看归档目录

15、LightDB包含哪些日志?

数据库日志:
位于$LTDATA/log目录中。
ltcluster日志:
位于$LTHOME/etc/ltcluster/下,仅高可用版本有。
keepalived日志:
位于/var/log/下,并且在$LTHOME/etc/keepalived/keepalived_lightdb.log有keepalived检测lightdb的心跳日志,仅高可用版本需启用keepalived。

16、查看数据库日志中的错误信息

LightDB日志中的错误信息包含ERRORFATAL标签,可以此为关键词从日志文件中过滤错误行。

单次查看当前错误日志

cd $LTDATA/log
cat lightdb-yyyy-mm-dd_hhmmss.log | grep -E 'ERROR|FATAL'

实时监控最新错误日志

cd $LTDATA/log
tail -fn 10 lightdb-yyyy-mm-dd_hhmmss.log | grep -E 'ERROR|FATAL'

17、查看是否开启了慢日志,开启与关闭慢日志

在LightDB中慢日志配置参数有两处:数据库自身和auto_explain插件,使用show可以查看这两个参数。

show log_min_duration_statement;    -- 数据库慢日志,默认值-1
show auto_explain.log_min_duration; -- auto_explain慢日志,默认值100ms

数据库慢日志仅记录SQL,auto_explain慢日志同时记录SQL和执行计划,二者参数值的含义完全相同:

  • -1表示关闭慢日志
  • 0表示启用慢日志,且记录所有SQL
  • 大于0(如100ms、1s)表示启用慢日志,且仅记录elapsed time大于等于该时间的SQL

在LightDB中,log_min_duration_statement默认值为-1,auto_explain.log_min_duration默认值为100ms(前提是auto_explain已启用,默认不启用),若在lightdb.conf中修改了这两个参数,不用重启数据库,仅需reload重新加载即可生效。

lt_ctl -D $LTDATA reload

如果希望启用auto_explain,则需要修改lightdb.conf中的shared_preload_libraries,在其中添加auto_explain,然后重启数据库。对于LightDB单机版,可以直接执行lt_ctl -D $LTDATA restart即可,但如果安装的是LightDB高可用或分布式,则务必按高可用和分布式的停止与启动步骤进行操作。

18、ltsql常见命令帮助和数据库视图信息

18.1 ltsql使用帮助

lightdb@hsfuttest=# \?
General
  \copyright             show LightDB usage and distribution terms
  \crosstabview [COLUMNS] execute query and display results in crosstab
  \errverbose            show most recent error message at maximum verbosity
  \g [(OPTIONS)] [FILE]  execute query (and send results to file or |pipe);
                         \g with no arguments is equivalent to a semicolon
  \gdesc                 describe result of query, without executing it
  \gexec                 execute query, then execute each value in its result
  \gset [PREFIX]         execute query and store results in ltsql variables
  \gx [(OPTIONS)] [FILE] as \g, but forces expanded output mode
  \q                     quit ltsql
  \watch [SEC]           execute query every SEC seconds

Help
  \? [commands]          show help on backslash commands
  \? options             show help on ltsql command-line options
  \? variables           show help on special variables
  \h [NAME]              help on syntax of SQL commands, * for all commands

-- 查看版本信息
ltsql -V 
ltsql -c "select version()"
select version();
-- 列表查看所有已安装的数据库
\l+
或者
ltsql -p 65534 -l
                                    List of databases
     Name      |  Owner  | Encoding |  Collate   |   Ctype    |     Access privileges     
---------------+---------+----------+------------+------------+---------------------------
 hsfut         | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | =Tc/lightdb              +
               |         |          |            |            | lightdb=CTc/lightdb      +
               |         |          |            |            | hsfut=CTc/lightdb
 hsfut_plpgsql | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | =Tc/lightdb              +
               |         |          |            |            | lightdb=CTc/lightdb      +
               |         |          |            |            | hsfut_plpgsql=CTc/lightdb
 lt_test       | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres      | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0     | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | =c/lightdb               +
               |         |          |            |            | lightdb=CTc/lightdb
 template1     | lightdb | UTF8     | en_US.utf8 | en_US.utf8 | =c/lightdb               +
               |         |          |            |            | lightdb=CTc/lightdb
(6 rows)

-- 执行操作系统命令
\! ls

-- 查看当前连接的数据库名称
select current_database();
-- 查看当前连接的用户名:
select * from current_user;
select user;
-- 列表浏览数据库实体对象
\d+ 

创建用户

创建用户
CREATE USER user2 WITH ENCRYPTED PASSWORD '123456';
\password [USERNAME] 

检验所创建的拥有者
\du uesr1

连接数据库
\c <sample_db_name> [username]

得到psql元命令实际执行的sql
psql -E 或者
\set ECHO_HIDDEN on|off

19、查看安装了哪些extension

  • 查看所有可用的extension
select * from pg_available_extensions;
  • 查看当前启用的extension
select * from pg_extension;

20、查看按大小排序的前20张表

-- 查出按大小(table_size + index_size)排序的前20张表,并分离table_size和index_size
SELECT
	table_name,
	pg_size_pretty(table_size) AS table_size,
	pg_size_pretty(index_size) AS index_size,
	pg_size_pretty(total_size) AS total_size
FROM (
	SELECT
		table_name,
		pg_table_size(table_name) AS table_size,
		pg_indexes_size(table_name) AS index_size,
		pg_total_relation_size(table_name) AS total_size
	FROM (
		SELECT table_schema || '.' || table_name AS table_name
		FROM information_schema.tables
	) AS all_tables
	ORDER BY total_size DESC
) AS pretty_sizes
LIMIT 20;

21、查看LightDB当前的整体负载

查看LightDB当前整体负载,可以简单地使用top命令查看CPU利用率、内存使用情况、IO等指标信息,也可以使用LightDB EM来实时监控LightDB与服务器主机的各项指标。

22、查看LightDB的生效配置,修改会话配置、全局配置

可以用show语句查看LightDB当前的生效配置,show语句有以下几种用法:

SHOW name;   -- 查看指定的para配置参数
SHOW ALL;    -- 查看所有配置参数
SHOW name%;  -- 查看前缀为name的配置参数
SHOW %name;  -- 查看后缀为name的配置参数
SHOW %name%; -- 查看名字中间包含name的配置参数

修改配置参数有两种级别:会话级和全局级。

-- 会话级修改,并非所有参数都支持会话级修改
SET [ SESSION | LOCAL ] configuration_parameter { TO | = } { value | 'value' | DEFAULT };

-- 全局修改有两种方法:一是修改postgresql.conf,二是使用下面的SQL语句,然后按要求reload或restart生效
ALTER SYSTEM SET configuration_parameter { TO | = } { value | 'value' | DEFAULT };

23、什么是vacuum?为什么要执行vacuum?怎么确定vacuum是否成功?

vacuum用于清理数据库表中的dead tuples,因为LightDB MVCC不使用undo日志,而是将update、delete修改或删除前的记录保留在表中,并打上一个标记,对于update还会插入一条更新后的新纪录,带有这种标记的tuple叫做dead tuple,也就是死元组。

当执行过checkpoint之后,之前的死元组就没有用了,vacuum就是用来清除这些无用的死元组的,如果长时间不进行vacuum,表中的死元组就会堆积的越来越多,导致表膨胀。

vacuum语句基本用法有两种,一种是直接执行vacuum,另一种是vcuum tablename,前者对当前database中的所有表进行清理,后者仅对指定的表进行清理,执行成功时,客户端会返回一行VACUUM信息。

24、查看最近的检查点执行时间

lt_controldata $LTDATA | grep "Time of latest checkpoint:"

25、怎么查看checkpoint执行频率?怎么查看auto vacuum频率?

show checkpoint_timeout;  -- 查看checkpoint频率
show autovacuum_naptime;  -- 查看autovacuum频率

26、lt_wal目录过大,怎么确定是否可以删除?如何删除?

先使用lt_controldata获得Latest checkpoint's REDO WAL file,如下所示。

$ lt_controldata $LTDATA | grep "Latest checkpoint's REDO WAL file"
Latest checkpoint's REDO WAL file:    000000010000000000000006

然后通过下面的语句清理归档

lt_archivecleanup $LTHOME/archive `lt_controldata $LTDATA | grep "Latest checkpoint's REDO WAL file" | awk '{print $6}'`

Latest checkpoint's REDO WAL file之前的WAL文件(包括已归档和未归档)都可以删除.

lt_archivecleanup -d $LTDATA/lt_wal last_checkpoint_redo_wal_file   # 删除未归档的WAL文件
lt_archivecleanup -d $LTHOME/archive last_checkpoint_redo_wal_file  # 删除已归档的WAL文件

27、查看LightDB启动时间

select * from pg_postmaster_start_time();

28、查看当前事务号

select * from pg_current_xact_id();

29、看LightDB实例概要信息

https://www.hs.net/lightdb/docs/html/functions-info.html

pg_control_checkpoint(), pg_control_init(), pg_control_system(), pg_control_recovery()

30、复制管理功能

https://www.hs.net/lightdb/docs/html/functions-admin.html#FUNCTIONS-ADMIN-BACKUP

31、其他管理功能函数

https://www.hs.net/lightdb/docs/html/functions-admin.html

32、高可用归档清理

高可用归档清理通过配置lightdb_archive_dir(归档目录) 和lightdb_archive_retention_size(归档目录中Latest checkpoint's REDO WAL file 之前的文件保留数,建议配置为10以上,具体根据磁盘空间和主备间延迟配置,尽可能大)使用。

如:Latest checkpoint's REDO WAL file 为000000010000000100000049,lightdb_archive_retention_size配为10,则清理小于 000000010000000100000039 的wal文件。

33、日志清理

日志清理通过配置lightdb_log_retention_age来清理,单位为分钟(可配置为3d,内部会转为分钟)。

如:配置lightdb_log_retention_age=7d,则只保留7天的日志,在切换新文件时清理旧文件,根据文件的最新更新时间来清理。

34、WAL文件缺失或被误删

如果不小心删除了wal文件,可通过pg_resetwal -f PGDATA重新初始化wal文件,但是会丢失事务日志以及数据不一致,因为可能有full checkpoint之前的数据丢失,极端情况下某些数据块丢失。

具体丢多少数据,可以通过lt_controldata输出中的latest checkpoint:

[lightdb@hs-10-20-30-199 bin]$ lt_controldata | grep -i checkpoint
Latest checkpoint location:           D4/78EFF8E8
Latest checkpoint's REDO location:    D4/78DE1390
Latest checkpoint's REDO WAL file:    00000001000000D400000003
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0:50116967
Latest checkpoint's NextOID:          57309
Latest checkpoint's NextMultiXactId:  783
Latest checkpoint's NextMultiOffset:  1565
Latest checkpoint's oldestXID:        482
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  50116967
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Mon 04 Jul 2022 08:35:03 PM CST

35、查看LightDB是否高可用、集群信息、主从节点

如果是单机版,则没有ltcluster库,可使用命令ltsql ltcluster尝试连接ltcluster库来确认,预期提示数据库不存在。单机版也不会有$LTHOME/etc/ltcluster/ltcluster.conf这个配置文件。

如果是高可用部署,使用主节点或从节点运行下面的命令查看集群节点信息:

ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf cluster show

示例结果:

 ID | Name    | Role    | Status    | Upstream | Location | Priority | Timeline | Connection string
----+---------+---------+-----------+----------+----------+----------+----------+-----------------------------------
 1  | node199 | primary | * running |          | default  | 100  | 1 | host=node199 port=5432 user=ltcluster dbname=ltcluster connect_timeout=2
 2  | node193 | standby |   running | node199  | default  | 100  | 1 | host=node199 port=5432 user=ltcluster dbname=ltcluster connect_timeout=2

也可以使用LightDB-EM查看是单机部署还是高可用部署。

36、判断集群健康状态

在主节点或从节点运行命令ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf cluster show展示的信息中没有WARNINGStatusUpstream字段没有出现?!符号。

   ID | Name     | Role    | Status    | Upstream| Location | Priority | Timeline | Connection string                                                      
   ----+---------+---------+-----------+---------+----------+----------+----------+--------------------------------
    1  | node199 | primary | * running |         | default  | 100      | 1        | 
    2  | node193 | standby |   running | node199 | default  | 100      | 1        | 

在各个节点运行命令ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf node check展示的各个检查项的均为OK

示例结果:

Node "node193":
Server role: OK (node is standby)
Replication lag: OK (0 seconds)
WAL archiving: OK (0 pending archive ready files)
Upstream connection: OK (node "node193" (ID: 2) is attached to expected upstream node "node199" (ID: 1))
Downstream servers: OK (this node has no downstream nodes)
Replication slots: OK (node has no physical replication slots)
Missing physical replication slots: OK (node has no missing physical replication slots)
Configured data directory: OK (configured "data_directory" is "/data1/data5432")

37、查看集群事件

在排查集群问题,或监控集群事件时,除了查看$LTHOME/etc/ltcluster/ltcluster.log,ltcluster在events表中记录了更清晰有效的信息。

可运行ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf cluster events查看集群事件,最新的事件排在最上面,示例结果如下:

 Node ID | Name    | Event           | OK | Timestamp           | Details                                                                                                  
----+---------+----------------------+----+---------------------+------------------------------------------
 1  | node199 | child_node_reconnect | t  | 2021-11-22 21:06:58 | standby node "node193" (ID: 2) has reconnected after 1303 seconds                    
 1  | node199 | child_node_reconnect | t  | 2021-11-22 21:06:58 | standby node "node193" (ID: 2) has reconnected after 1303 seconds                    
 2  | node193 | standby_register     | t  | 2021-11-22 21:06:55 | standby registration succeeded; upstream node ID is 1                                                    
 2  | node193 | standby_recovery     | t  | 2021-11-22 21:06:42 | reconnected to local node "node193" (ID: 2), marking active                          
 2  | node193 | standby_clone        | t  | 2021-11-22 21:05:44 | cloned from host "node199", port 5432; backup method: lt_basebackup; --force: N

上述命令实际读取了ltcluster.events这张表,所以也可以通过SQL直接查询:

$ ltsql ltcluster # 连接ltcluster库
ltsql (13.3-21.2)
Type "help" for help.

ltcluster=# select * from ltcluster.events ;
 node_id |           event            | successful |        event_timestamp        |                                                  details                                                  
---------+----------------------------+------------+-------------------------------+---------------------------
       1 | cluster_created            | t          | 2021-11-21 22:17:20.421939+08 | 
       1 | primary_register           | t          | 2021-11-21 22:17:20.423033+08 | 
       2 | standby_clone              | t          | 2021-11-21 22:27:39.853675+08 | cloned from host "node199", port 5432; backup method: lt_basebackup; --force: N
       2 | standby_register           | t          | 2021-11-21 22:31:49.270459+08 | standby registration succeeded; upstream node ID is 1
       1 | child_node_reconnect       | t          | 2021-11-21 22:31:55.155461+08 | standby node "node193" (ID: 2) has reconnected after 440552 seconds
       1 | child_node_disconnect      | t          | 2021-11-21 22:35:49.769979+08 | standby node "node192" (ID: 2) has disconnected

38、查看主从同步模式与延时

可在主节点执行select * from pg_stat_replication得到各个节点的实时同步状态信息。

lightdb@postgres=# select * from pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid              | 1135698
usesysid         | 21741
usename          | ltcluster
application_name | lightdbCluster1019691835468
client_addr      | 10.19.69.183
client_hostname  | 
client_port      | 38320
backend_start    | 2022-04-25 20:26:56.4993+08
backend_xmin     | 
state            | streaming
sent_lsn         | 23/2A3ED548
write_lsn        | 23/2A3ED548
flush_lsn        | 23/2A3ED548
replay_lsn       | 23/2A3ED548
write_lag        | 00:00:00.000144
flush_lag        | 00:00:00.000915
replay_lag       | 00:00:00.00093
sync_priority    | 1
sync_state       | sync
reply_time       | 2022-05-06 17:28:27.523848+08

如果是多备机的情况下,每个备机都有一条记录。 通过write_lag,flush_lag,replay_lag可以查看当前主从同步延迟信息。

可以从表ltcluster.monitoring_history中获取各个时间段的延时:

ltcluster=# select * from ltcluster.monitoring_history order by last_monitor_time limit 10 ;
 primary_node_id | standby_node_id |       last_monitor_time       |        last_apply_time        | last_wal_primary_location | last_wal_standby_location | replication_lag | apply_lag 
-----------------+-----------------+-------------------------------+-------------------------------+---------------------------+---------------------------+-----------------+-----------
               1 |               2 | 2021-12-21 16:57:48.537956+08 | 2021-12-21 16:57:48.52187+08  | 0/60012308                | 0/60012308                |               0 |         0
               1 |               2 | 2021-12-21 16:57:50.561467+08 | 2021-12-21 16:57:50.294248+08 | 0/6001C540                | 0/6001C540                |               0 |         0
               1 |               2 | 2021-12-21 16:57:52.577251+08 | 2021-12-21 16:57:52.55301+08  | 0/6001F1B0                | 0/6001F1B0                |               0 |         0
               1 |               2 | 2021-12-21 16:57:54.590478+08 | 2021-12-21 16:57:53.66048+08  | 0/60020878                | 0/60020878                |               0 |         0
               1 |               2 | 2021-12-21 16:57:56.6056+08   | 2021-12-21 16:57:55.944149+08 | 0/60023598                | 0/60023598                |               0 |         0
               1 |               2 | 2021-12-21 16:57:58.618428+08 | 2021-12-21 16:57:58.19143+08  | 0/600278E0                | 0/600278E0                |               0 |         0
               1 |               2 | 2021-12-21 16:58:00.638982+08 | 2021-12-21 16:58:00.615274+08 | 0/600C3150                | 0/600C3150                |               0 |         0
               1 |               2 | 2021-12-21 16:58:02.686736+08 | 2021-12-21 16:58:01.813462+08 | 0/6023B0A8                | 0/6023B0A8                |               0 |         0
               1 |               2 | 2021-12-21 16:58:04.712443+08 | 2021-12-21 16:58:04.117613+08 | 0/6023FA10                | 0/6023FA10                |               0 |         0
               1 |               2 | 2021-12-21 16:58:06.730236+08 | 2021-12-21 16:58:06.310637+08 | 0/60242C48                | 0/60242C48                |               0 |         0

也可以从LightDB-EM监控页面查看延时。

39、集群复制级别

不同的业务场景对数据库主备一致性有不同的要求。一致性越高对性能影响越大。用户可通过配置synchronous_commit来达到不同级别的一致性。

# 同步模式,在主节点修改
synchronous_commit = 'on'
synchronous_standby_names = '*'

# 异步模式,在主节点修改
synchronous_commit = 'local'
synchronous_standby_names = ''

# 修改后,主节点调用reload生效
lt_ctl -D $LTDATA reload

下表概括了 synchronous_commit 不同设置对应不同的一致性级别:

synchronous_commit设置 本地提交持久化 备库提交持久化(数据库崩溃) 备库提交持久化(OS崩溃) 备库查询一致
remote_apply
on
remote_write
local
off

更详细的synchronous_commitsynchronous_standby_names请参考LightDB官方文档。

40、主备切换

在需要维护primary节点时,可做switchover,互换主从角色。switchover操作的内部执行比较复杂,非必要尽量不要执行。

具体操作时,请严格按照下面步骤执行:

  1. 主备之间需要有SSH免密访问(LightDB安装时有要求)

  2. 尽量减少应用程序的访问

  3. 检查主备间的网络状况是否良好,确保有良好的网络

  4. 确保当前主备之间没有明显的复制延迟,尤其在集群复制级别较低的情况下(参考 [3.4节](###3.4 查看主从同步模式与延时),[3.5节](###3.5 集群复制级别 ))

  5. 检查等待归档的文件是否有积压, 可通过下面的命令来检查

    ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf node check --archive-ready
    
    

    确保输出是: OK (0 pending archive ready files)

    如果是其他输出,则应检查归档进程是否正常。如果归档正常,则可以等待一会儿再试下。

  6. 使用dry-run试运行switchover命令,查看输出是否有警告和错误

ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf standby switchover --siblings-follow --dry-run

如果最后一行信息为:prererequisites for executing STANDBY SWITCHOVER are met,则表示成功

  1. 在备机上正式执行switchover, 打开最详细的日志级别(注意保存输出日志)
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf standby switchover \
	--log-level=DEBUG --verbose --siblings-follow
  1. 在各节点上查看集群状态,确认各节点执行结果中primary和standby角色确实已互换
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service status

输出要确保没有警告和错误信息

  1. 查看paused状态是否为no

确认Paused列为no (如果switchover过程出现异常,经过处理后,switchover成功, 此时在这一步可能处于yes)

如果为yes,则执行

ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service unpause
  1. 如果使用同步模式,则需要把新主改成同步模式(和旧主一样),新备改成local模式(参考[3.5节](###3.5 集群复制级别))
  2. 确认VIP是否切换到新的主机上(参考[3.11节](###3.11 如何查看VIP当前在哪个节点 ))
  3. 确认应用程序是否可以正常访问数据库

41、故障恢复,主节点重新加入作为从节点

当主库发生故障(如宕机)failover后,备库会自动提升为新主库,以确保集群继续可用。在原主库修复后, 可以以备机的方式加入集群,是的整个集群仍然保持高可用正常状态。

在原主库故障修复后,数据库本身会仍然运行主模式,我们需要执行rejoin命令,rejoin命令会把数据库改为备模式, 并且从新主把最新的WAL日志同步过来,确保数据一致。

在本节后续描述中,主库指的是新主库(即原备机提升后的主库), 备库指的是原主库(发生宕机的节点)。

以下是具体操作步骤:

  1. 确认主库是正常运行状态,而备库是停止状态

  2. 同步归档日志,把主库的归档日志同步到备库中,归档目录为: $LTHOME/archive 备库中的原有归档日志应备份到其他地方或者删除。

  3. 在备库上执行以下命令,检查当前是否满足rejoin条件(注意把命令中的<primary_host>替换为主库的ip地址)

    ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf node rejoin \
        -d 'host=<primary_host> dbname=ltcluster user=ltcluster' \
        --verbose --force-rewind --dry-run
    

    确认输出有INFO: prerequisites for executing NODE JOIN are met 并且无警告或者错误信息。

  4. 正式执行rejoin (注意把命令中的<primary_host>替换为主库的ip地址)

    ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf node rejoin \
        -d 'host=<primary_host> dbname=ltcluster user=ltcluster' \
        --verbose --force-rewind
    

42、什么时候会rejoin失败、如何确定肯定无法rejoin了?无法rejoin的节点如何重新加入?

如果备机离线时间较久,必要的WAL日志在主上已经被移除,则rejoin会失败。此时需要使用standby clone操作来恢复集群,standby clone的原理是从主上把整个库拷贝过来, 在数据库较大的情况下耗时会比较久。

standby clone的步骤如下:

  1. 确认备库LightDB已停止

  2. 确认ltclusterd是否启动,若不存在则启动它

    ps aux | grep ltcluster
    ltclusterd -d -f $LTHOME/etc/ltcluster/ltcluster.conf -p $LTHOME/etc/ltcluster/ltclusterd.pid
    
  3. 清空备库实例目录($LTDATA)下的内容(若有需要,清空前可先备份)

  4. 清空备库归档目录($LTHOME/archive)下的内容(若有需要,清空前可先备份)

  5. clone试运行,将new_primary_host替换为原备,也就是新主的host

    ltcluster -h new_primary_host -U ltcluster -d ltcluster \
        -f $LTHOME/etc/ltcluster/ltcluster.conf standby clone --dry-run
    
  6. 确认试运行结果显示all prerequisites for "standby clone" are met

  7. clone实例目录,new_primary_host同上, 如果库比较大,这里执行时间会很长,具体执行时间取决于网络情况和数据量大小 在我们的测试中800G左右的库大概需要一个小时 我们建议采用异步的方式执行这个命令,以避免执行过程中终端意外关闭的影响。 另外我们开启了最详细的日志级别,以便协助定位问题

    nohup ltcluster -h new_primary_host -U ltcluster -d ltcluster \
          -f $LTHOME/etc/ltcluster/ltcluster.conf \
          standby clone -F \
          --log-level=DEBUG --verbose \
          >standby_clone.log  2>&1 &
    
  8. 把主库的归档目录下的所有文件复制到备库的归档目录中($LTHOME/archive)

  9. 启动数据库

    lt_ctl -D $LTDATA start
    
  10. 重新注册为standby

    ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf standby register -F
    

43、什么是timeline,timeline什么时候变化?如何查看当前的timeline id?

timeline可以认为是数据库wal的分支(类比版本管理系统,比如svn)。

当进行一次恢复,或发生主备切换,会生成一个timeline。每个timeline有一个id,从1开始编号。当生成一个新的timeline时,它的wal是独立的,不会覆盖其它timeline的wal,这就保证了可以多次来回恢复。如果没有timeline,即恢复后wal覆盖写,则只能一直往“以前”恢复。

可以查看lt_wal中的history文件,来确定当前有几个timeline、各自创建时的LSN、创建的原因,如

$ cat ./data/defaultcluster/lt_wal/00000004.history
1	16/F20000A0	no recovery target specified

2	16/F50000A0	no recovery target specified

3	16/F60000A0	no recovery target specified

序号最大的history文件即是当前timeline id。

可以通过sql查看当前timeline id: ltsql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM";或在主库执行select substring(pg_walfile_name(pg_current_wal_lsn()), 1, 8);

高可用命令ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf cluster show获取的timeline是当前最近做checkpoint的timeline,可能不是最新的timeline。

44、当出现双主时如何处理

如果出现双主,把老主停掉,重新加入集群作为standby。参考node rejoin章节,如果rejoin失败,老主通过standby clone重新加入集群。

45、如何查看VIP当前在哪个节点

使用命令ip a可看到vip是否在当前节点,比如

$ ip a | grep 251
    inet 10.19.36.251/32 scope global enp2s0f0

如果grep没有匹配行,则vip不在当前节点。

可以在keepalived.conf中查看vip配置,比如

$ cat $LTHOME/etc/keepalived/keepalived.conf
...
    interface enp2s0f0
...
    virtual_ipaddress {
        10.19.36.251
    }
...

46、如何触发VIP漂移

在以下场景会触发VIP漂移:

  • 主库崩溃、意外停止,导致自动主从切换 (failover)
  • 手动进行主从切换 (switchover)

47、为什么会出现VIP同时在两个节点?

如果主从之间网络出现问题,从节点可能误判主节点故障,把自己提升,这时会出现两个VIP。

建议集群中加入witness节点,避免网络问题引起主从切换或从节点自动切主。

48、高可用环境如何重启主库?

主库因修改数据库参数或其他原因需要重启,可以按以下步骤操作。(注意: 重启期间数据库不提供服务)

  1. 先停止从库的keepalived(重要),在root用户下执行以下命令
# 1. 获得备库keepalived进程pid
cat /var/run/keepalived.pid

# 2. 杀死keepalived进程
kill keepalived_pid

# 3. 确认keepalived进程确实已不存在
ps aux | grep keepalived
  1. 主库重启,需要在lightdb用户下执行
# 1. 暂停ltclusterd,防止自动failover
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service pause

# 2. 查看集群状态,确认primary的Paused?状态为yes
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service status

# 3. 先断开所有连接到数据库的客户端和应用程序(否则数据库将stop failed),然后停止主库
lt_ctl -D $LTDATA stop  # 默认会回滚所有未断开的连接

# 如果有连接存在导致stop failed,则可以尝试使用
lt_ctl -D $LTDATA stop -m smart

# 如果仍然stop failed,且因条件限制无法或不希望断开所有客户端连接,则可以使用-m immediate强制停止数据库,此方式下没有回滚连接,即强制断开、强制停止,没有完全shutdown,会导致在启动时recovery
lt_ctl -D $LTDATA stop -m immediate

# 4. 等待数据库停止成功,确认步骤3执行结果中出现server stopped信息

# 5. 修改数据库参数,或做其他事情

# 6. 启动主库
lt_ctl -D $LTDATA start

# 7. 等待数据库启动成功,确认步骤6执行结果中出现server started的信息

# 8. 恢复ltclusterd
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service unpause

# 9. 查看集群状态,确认primary的Paused?状态为no
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service status
  1. 从库重新启动keepalived(需root用户),启动方法请参照本文档5.3。

49、高可用环境如何重启从库?

备库因修改数据库参数或其他原因需要重启,可以在lightdb用户下按以下步骤操作。

# 1. 暂停ltclusterd,防止自动failover
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service pause

# 2. 查看集群状态,确认standby的Paused?字段为yes
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service status

# 3. 先断开所有连接到数据库的客户端和应用程序(否则数据库将stop failed),然后停止备库
lt_ctl -D $LTDATA stop  # 默认会回滚所有未断开的连接

# 如果有连接存在导致stop failed,则可以尝试使用
lt_ctl -D $LTDATA stop -m smart

# 如果仍然stop failed,且因条件限制无法或不希望断开所有客户端连接,则可以使用-m immediate强制停止数据库,此方式下没有回滚连接,即强制断开、强制停止,没有完全shutdown,会导致在启动时recovery
lt_ctl -D $LTDATA stop -m immediate

# 4. 等待数据库停止成功,确认步骤3执行结果中出现server stopped信息

# 5. 修改数据库参数,或做其他事情

# 6. 启动备库
lt_ctl -D $LTDATA start

# 7. 等待数据库启动成功,确认步骤6执行结果中出现server started的信息

# 8. 恢复ltclusterd
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service unpause

# 9. 确认standby的Paused?字段为no
ltcluster -f $LTHOME/etc/ltcluster/ltcluster.conf service status

50、高可用归档清理与lt_probackup备份归档清理

当同时使用高可用归档与lt_probackup备份归档时建议建立两个归档目录,归档两份,分别给高可用和备份使用,不然如果使用同一个,然后只开启备份的清理,有可能出现误删高可用所需的wal文件;只开启高可用的归档清理,可能导致误删备份所需的wal文件。

高可用归档清理参见2.23一节。

51、集群启停管理脚本

可以通过使用 lightdb_service.py 来进行集群的启停及简单的状态检测。脚本在 $LTHOME/bin/ 下,依赖于uninstall目录下的uninstallFile.json 来获取集群信息。 此脚本在lightdb用户下执行,lightdb需要支持sudo免密。

python 版本需为 python3。使用方式如下:

usage: lightdb_service.py [-h] [-F <install_info>]
                          [-c {start,stop,restart,status}] [-C | -D] [-P | -S]
                          [-n <node_info>] [--dry-run] [-f]
                          [-B <parallel_processes>] [-v] [-q] [-l <directory>]

use for start/stop/restart LightDB service

optional arguments:
  -h, --help            show this help message and exit
  -F <install_info>, --filename <install_info>
                        specifies the path to a json file containing
                        installation information(uninstall/uninstallFile.json)
  -c {start,stop,restart,status}, --command {start,stop,restart,status}
                        start/stop/restart/status lightdb service
  -C, --cn_only         only start/stop/restart coordinator node
  -D, --dn_only         only start/stop/restart data node
  -P, --primary_only    only start/stop/restart primary node for primary
                        restart
  -S, --standby_only    only start/stop/restart standby node for standby
                        restart
  -n <node_info>, --node <node_info>
                        only start/stop/restart specified node, node_info
                        formart: ip:port
  --dry-run             show what would happen for action, but don't execute
                        it
  -f, --force           force stop of cluster even if some nodes are in
                        incorrect state, skip incorrect nodes
  -B <parallel_processes>, --parallel <parallel_processes>
                        number of segment hosts to run in parallel. Default is
                        1
  -v, --verbose         debug print
  -q, --quiet           suppress status messages for stdout logging
  -l <directory>, --log_dir <directory>
                        Logfile directory, default is /tmp/ltAdminLogs
  1. 启动集群

    python lightdb_service.py -c start
    
  2. 停止集群

    python lightdb_service.py -c stop
    
  3. 重启集群

    python lightdb_service.py -c restart
    
  4. 查看集群状态

    python lightdb_service.py -c status
    
  5. 只启停主

    启停时会保证主备状态不变

    python lightdb_service.py -c start/stop/restart --primary_only
    
  6. 只启停备

    python lightdb_service.py -c start/stop/restart --standby_only
    
  7. 只启停CN节点

    python lightdb_service.py -c start/stop/restart --cn_only
    
  8. 只启停DN节点

    python lightdb_service.py -c start/stop/restart --dn_only
    
  9. 只启停某个节点

    python lightdb_service.py -c start/stop/restart -n 10.20.148.122:54333
    
  10. 强制停止

    当集群状态不对时,stop 会失败,此时如果仍需停止集群可以使用-f --force

    python lightdb_service.py -c stop -f
    
  11. 试运行

python lightdb_service.py -c xxx --dry-run 

52、修改有视图依赖的表字段属性

目前在lightdb中不能通过 alter table 语句直接修改有视图依赖的表字段的某些属性(比如字段类型 int -> number)。 可以采用如下方式修改:

begin;
select deps_save_and_drop_dependencies('public', 'test');
alter table test modify key1 number;
select deps_restore_dependencies('public', 'test');
commit;

原理调用deps_save_and_drop_dependencies删除依赖的视图并保存创建语句到lt_catalog.deps_saved_ddl表, 然后在alter table后调用deps_restore_dependencies获取创建语句重新创建视图。

note

调用函数设置的schema_name和table_name需要与实际相符,一般为小写(因为lightdb内部会都转为小写),对于craete table "Test"(key1 int);这种需传入Test.

53、create or replace view 修改视图无法增加字段

目前需要替换为先使用drop view if exist, 然后在执行create。

54、LightDB适配MySQL需要注意点

  1. 列别名:MySQL 中支持 select a 'authorized' from test; LightDB中需要使用如下语句,列别名由单引号换做使用双引号或 as: select a as authorized from test
  2. 表删除:MySQL 中支持 delete my_table from my_table where ...; delete后不支持接表名:delete from my_table where ...
  3. 双竖线:MySQL 中支持 where (a is NULL || a = 0)双竖线做逻辑操作符,lightdb中双竖线为字符串拼接,双竖线可以换为or
  4. DUPLICATE语法:可以使用ON conflict进行替换:INSERT INTO tb_rpa_resource_index(instance_id, user_id, resource_id, resource_type, resource_idx) VALUES ('m', 'm', 'm', 1, 1) ON conflict(instance_id) DO UPDATE SET user_id = EXCLUDED.user_id, resource_id = EXCLUDED.resource_id, resource_type = EXCLUDED.resource_type, resource_idx = EXCLUDED.resource_idx
  5. replace into语法:可以使用ON conflict进行替换:INSERT INTO tb_see_sync(data_id,type,node_id,update_datetime,status,code,msg,version) VALUES ('m', 'm', 'm', now(),'m','m','m',1) ON conflict(data_id) DO UPDATE SET type = EXCLUDED.type, node_id = EXCLUDED.node_id, update_datetime = EXCLUDED.update_datetime, update_datetime = EXCLUDED.update_datetime, status = EXCLUDED.status, code = EXCLUDED.code, msg = EXCLUDED.msg, version = EXCLUDED.version
  6. 多表关联删除:可以使用with子句:with x as (delete from tb_cdm_relation_class a using tb_cdm_relation_class b where a.class_id = b.parent_class_id and a.source_class_id in ('1') returning a.*) delete from tb_cdm_relation_class c using x where c.parent_class_id = x.class_id;
  7. 多表关联更新:可以使用:update tb_rolepower a set a.power_id = b.id from tb_menu b where b.sn = a.power_id;
  8. MySQL转Lightdb的sql分模块导出导入:ltdump -t tablename1 -t tablename2
  9. interval $1 months支持:可以使用make_interval(months=>$1)代替
  10. MySQL中datetime转到lightdb中的timestamp类型,不管插入数据如何只精确到秒级:lightdb中timestamp换为timestamp(0)

55、如何通过java jdbc调用LightDB存储过程

https://jdbc.postgresql.org/documentation/callproc/

package com.hundsun.lightdb.callProcedure;

import org.junit.Test;

import java.sql.*;
import java.util.Properties;

public class testCallPgProcedure {
    @Test
    public void testCallProcedure() {
        try {
            Class.forName("org.postgresql.Driver").newInstance();
//            String url = "jdbc:postgresql://10.20.30.111:5435/database_name?currentSchema=schema_name";// 数据库名
            String url = "jdbc:postgresql://10.20.30.111:5435/database_name";// 数据库名
            Properties props = new Properties();
            // :TODO 支持调用存储过程,设置这个数据库配置项 escapeSyntaxCallMode
            //  ensure EscapeSyntaxCallmode property set to support procedures if no return value
            props.setProperty("escapeSyntaxCallMode", "callIfNoReturn");
            props.setProperty("user", "lightdb");
            props.setProperty("password", "lightdb");
            Connection conn = DriverManager.getConnection(url, props);

            CallableStatement proc = conn.prepareCall("{call sp_jy( ? ,?)}");
            proc.setString(1, "第一个参数");
            proc.registerOutParameter(1,Types.VARCHAR);
            proc.registerOutParameter(2,Types.VARCHAR);
            proc.setString(2," ");
            proc.execute();
            String string = proc.getString(1);
            String string1 = proc.getString(2);
            System.out.println("string = " + string);
            proc.close();
            conn.close();
        } catch (SQLException sqe) {
            System.out.println("Unexpected exception : " + sqe.toString()
                    + ", sqlstate = " + sqe.getSQLState());
            System.exit(1);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

}

LightDB22.3版本Oracle模式下,如何设置search_path?

首先确认下您的数据库是什么模式,执行下面语句,可以看到结果为Oracle,那么此环境为Oracle模式数据库

lightdb@lt_test=# show %compatible_type% ;
 lightdb_syntax_compatible_type 
--------------------------------
 Oracle
(1 row)

如果通过ltsql、dbeaver等客户端工具登录数据库,默认情况search_path如下

lightdb@lt_test=# show search_path ;
         search_path         
-----------------------------
 "$user", public, lt_catalog
(1 row)

需要在ltsql、dbeaver会话级别设置search_path,方能使用Oracle兼容等函数、数据类型等特性

lightdb@lt_test=# set search_path =  "$user", oracle, public,lt_catalog;
或者
lightdb@lt_test=# set search_path =  "$user", public, oracle, lt_catalog;
lightdb@lt_test=# show search_path ;
             search_path             
-------------------------------------
 "$user", public, oracle, lt_catalog
(1 row)

LightDB中当前schema由search_path决定,因此设置当前schema和设置search_path方法是一样了。jdbc提供以下两种方式。

options方式(推荐此方式)!!!

jdbc连接参数中,可以在options中指名guc参数,格式如下:options=-c guc参数名=参数值,其中options后面的值需要encode。如设置语句超时时间的连接字符串如下:

jdbc:postgresql://localhost:5432/lt_test?options=-c%20statement_timeout=90000

而search_path是guc参数的一部分,所以也可以设置search_path。search_path和statement_timeout一起设置如下:

jdbc:postgresql://localhost:5432/lt_test?options=-c%20search_path=\"$user\",public,oracle,lt_catalog%20-c%20statement_timeout=90000

这种方式必须提供完整的search_path列表,不会自动包含public schema。其效果和ltsql中执行set search_path一致。

currentSchema方式,jdbc提供了currentschema参数用于设置当前schema

jdbc:postgresql://localhost:5432/lt_test?currentSchema=\"$user\", oracle

@Test
  public void currentSchema() throws SQLException {
    connection = DriverManager.getConnection("jdbc:postgresql://10.20.30.11:5432/fund60?currentSchema=\"$user\", oracle", "username", "password");
    preparedStatement =  connection.prepareStatement("show search_path");
    resultSet = preparedStatement.executeQuery();
    while (resultSet.next()){
      String searchPath = resultSet.getString(1);
      System.out.println(searchPath);
    }
  }

此时,jdbc会自动补充public到search_path中。实际search_path是"$user", oracle, public, lt_catalog 。文档地址:https://jdbc.postgresql.org/documentation/use/#connection-parameters

同理,如果您的数据库为MySQL模式,将上面的oracle替换为mysql即可。

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published