9

【参赛作品7】PostgreSQL/openGauss数据库易犯的十大错误

 3 years ago
source link: https://my.oschina.net/gaussdb/blog/5115832
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

总结十点PostgreSQL/openGauss数据库中容易犯的错误。

1.同时设置日志行前缀和csvlog格式

比较常见大家同时配置下面这两个参数

log_line_prefix = '%m %u %d %p'
log_destination='csvlog'
  • %m是带毫秒的时间戳
  • %u是用户名
  • %d是数据库名
  • %p是进程ID

然后当我们配置为csvlog日志时,日志行的内容项是固定的,所以当我们需要配置日志前缀,精简日志行的内容项时,log_destination不能配置为csvlog。下面是正确的配置:

log_destination='stderr'
log_line_prefix = '%m %u %d %p'

2.不符合预期的日志轮换策略

日志轮换策略可以通过log_rotation_size参数按日志文件大小控制或者通过log_rotation_age参数按时间控制,但下面这四个参数需要合理组合使用。

log_filename
log_truncate_on_rotation
log_rotation_age
log_rotation_size
  • 方案一:每天生成一个新的日志文件

    log_filename='postgresql-%Y-%m-%d.log'
    log_truncate_on_rotation=off
    log_rotation_age=1d
    log_rotation_size=0
    
  • 方案二:写满固定大小(如10MB),则进行切换

    log_filename='postgresql-%Y-%m-%d_%H%M%S.log'
    log_truncate_on_rotation=off
    log_rotation_age=0
    log_rotation_size=10MB
    

    这种方案我们一般是为了根据时间去查看日志,文件名根据日志量可以设置到时分秒,但这里设置log_rotation_size并不能严格控制固定大小。

  • 方案三:保留固定天数的日志并循环覆盖,例如固定一周或者固定一个月

    log_filename='postgresql-%u.log'
    log_truncate_on_rotation=on
    log_rotation_age=1d
    log_rotation_size=0
    

log_filename常见的通配符变量

  • %u是星期的数字表示,范围是[1,7],1代表星期一
  • %w也是星期的数字表示,范围是[0,6],0代表星期天
  • %d是月份中的天数表示,范围是[01,31]

生产环境第三种方案更合适一些。

3.同步复制表的序列

看看下面这个例子,我们创建test表使用serial自增序列类型,系统帮我们生成了test_id_seq序列。

postgres=# create table test(id serial primary key,name varchar unique);
CREATE TABLE
postgres=# \d test
                                 Table "public.test"
 Column |       Type        | Collation | Nullable |             Default              
--------+-------------------+-----------+----------+----------------------------------
 id     | integer           |           | not null | nextval('test_id_seq'::regclass)
 name   | character varying |           |          | 
Indexes:
    "test_pkey" PRIMARY KEY, btree (id)
    "test_name_key" UNIQUE CONSTRAINT, btree (name)

当我们复制t_test表时,test表的序列引用也同时复制过来了,可以使用虚拟生成列来解决这个问题。

postgres=# create table t_test(like test including all);
CREATE TABLE
postgres=# \d t_test
                                Table "public.t_test"
 Column |       Type        | Collation | Nullable |             Default              
--------+-------------------+-----------+----------+----------------------------------
 id     | integer           |           | not null | nextval('test_id_seq'::regclass)
 name   | character varying |           |          | 
Indexes:
    "t_test_pkey" PRIMARY KEY, btree (id)
    "t_test_name_key" UNIQUE CONSTRAINT, btree (name)

openGauss对PG的这个问题做了修复,下面是openGauss复制t_test时,序列按表名做了区分。

omm=# \d t_test
                              Table "public.t_test"
 Column |       Type        |                      Modifiers                      
--------+-------------------+-----------------------------------------------------
 id     | integer           | not null default nextval('t_test_id_seq'::regclass)
 name   | character varying | 
Indexes:
    "t_test_pkey" PRIMARY KEY, btree (id) TABLESPACE pg_default
    "t_test_name_key" UNIQUE CONSTRAINT, btree (name) TABLESPACE pg_default

4.跳变的序列值

创建序列seq1,设置cache为10,session A获取下一个值为1.

postgres=# create sequence seq1 cache 10;
CREATE SEQUENCE
postgres=# select nextval('seq1');
 nextval 
---------
       1
(1 row)

session B查询获取下一个值为11

postgres=# select nextval('seq1');
 nextval 
---------
      11
(1 row)

序列值插入为了保证连续性,要设置cache为1。

5.从任意库查询pg_stat_statements模块统计信息

pg_stat_statements模块用来跟踪SQL语句的执行统计信息,我们如果把该模块安装到postgres数据库,就只能连到postgres数据库进行查询,除非其它数据库也安装了该模块,否则会提示报错找不到。

无论任何操作,都需要连接到一个数据库,即使我们只想创建一个全局的数据库用户,所以选对数据库特别重要。

6.truncate操作理解为DML语句

log_statement参数控制日志记录级别,有4个选项:none、ddl、mod、all。开启ddl,它会记录 create、alter和drop相关的语句,但不记录truncate。

truncate在Oracle中属于DDL语句,在PostgreSQL中属于DML语句。因此,当我们使用DDL日志记录语句时,无法记录到Truncate。

7.认为数据库的owner可以管理其下所有对象

数据库、模式、表的都有自己的owner,他们都属于实例中的对象,数据库owner只是具有数据库这个对象的CTc权限。数据库的默认权限为:

  • 允许public角色连接,即允许任何人连接。
  • 不允许除了超级用户和owner之外的任何人在数据库中创建schema。
  • 会自动创建名为public的schema,这个schema的所有权限已经赋予给public角色,即允许任何人在里面创建对象。

schema使用注意事项:

schema的owner默认是该schema下的所有对象的owner,但是允许用户在别人的schema下创建对象,所以一个对象的owner和schema的owner可能不同,都有drop对象的权限。

8.认为public模式下的对象可以互相访问

public模式只是允许任何人在里面创建对象并管理自己的对象,并不能查看别人创建的对象。

9.创建索引时起名为表名称

单个数据库里,索引和表的名称不能重复,因为他们都属于relation。

postgres=# create index a on a(id);
ERROR:  relation "a" already exists

10.把walsender当作主库

通常我们从操作系统层查看主库有walsender,备库有walreceiver,并且walsender信息中可以看到备库的IP地址,可以初步判断主备状态正常。

但请注意有walsender或者数据库中能查到pg_stat_replication视图并不能断定是主库,仅在一主一备环境可以这样简单判断,下面的图可以看出,虽然有walsender,但它也是个备库。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK