稳定性与性能规范
【强制】在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
【强制】游标使用后要及时关闭。
【强制】两阶段提交的事务,要及时提交或回滚,否则可能导致数据库膨胀。
【强制】不要使用delete 全表,性能很差,请使用truncate代替,(truncate是DDL语句,注意加锁等待超时)。
【强制】应用程序一定要开启autocommit,同时避免应用程序自动begin事务,并且不进行任何操作的情况发生,某些框架可能会有这样的问题。
【强制】高并发的应用场合,务必使用绑定变量(prepared statement),防止数据库硬解析消耗过多的CPU资源。
【推荐】不建议使用unlogged table,因为unlogged table不写WAL日志,备库无法同步数据,但是如果你的数据不需要持久化,则可以考虑使用unlogged table来提升数据的写入和修改性能。
【强制】秒杀场景,一定要使用 advisory_lock先对记录的唯一ID进行锁定,拿到AD锁再去对数据进行更新操作。 拿不到锁时,可以尝试重试拿锁。
【强制】在函数中或程序中,不要使用count(*) 判断是否有数据,对于大表会很慢。 建议的方法是limit 1;
【强制】对于高并发的应用场景,务必使用程序的连接池,否则性能会很低下。
如果程序没有连接池,建议在应用层和数据库之间架设连接池,例如使用pgbouncer或者pgpool-II作为连接池。
【强制】程序务必有重连机制,如果没有重连机制,一个长期空闲的连接可能会被网络层设备当成无效会话强制中断掉。即使设置tcp_keepalives_idle, tcp_keepalives_interval, tcp_keepalives_count等较短的TCP心跳,也不一定能覆盖所有场景。
建议有重连机制,建议在使用长时间未被使用的连接前使用select 1; 探测一下是否连接正常,如果不正常,则重连。建议使用select 1; 作为连接的定期心跳。
【强制】当业务有近邻查询的需求时,务必对字段建立GIST或SP-GIST索引,加速近邻查询的需求。
【推荐】可以预估SQL执行时间的操作,建议设置语句级别的超时,可以防止雪崩,也可以防止长时间持锁。
例如:set local statement_timeout= '10s'
【推荐】应该尽量在业务层面避免死锁的产生,例如一个用户的数据,尽量在一个线程内处理,而不要跨线程(即跨数据库会话处理)。
【索引】
-
选择区分度高的列建立索引,区分度越高越好;
-
复合索引选择利用率高的字段靠前,从左到右匹配;⽐如索引 idx_c1_c2_c3 (c1,c2,c3),相当于创建了(c1)、(c1,c2)、(c1,c2,c3) 三个索引,where 条件包含 上面三种情况的字段⽐较可以用到索引且效率比较高,但像where c2=b and c3=c或者 where c3=c 等条件查询虽然也可以使用到索引,但是需要扫描更多的索引块,查询效率会降低;
-
复合索引如果区分度足够高时,不需要所有的条件都建索引;比如区分度不大的枚举类字段,如账户状态、客户性别等;
-
优先考虑覆盖索引,避免冗余索引;比如已存在(A,B,C)时,不需要再建(A,B);主健字段不应再建索引;
-
索引并不是越多越好,单张表的索引数量控制在5个以内,索引中的字段数建议不超过5个,唯一索引建议3个以内,过多的索引会导致优化器选择偏差
-
尽量不要在频繁更新的列上创建索引;
-
ORDER BY,GROUP BY,DISTINCT的字段需要添加在索引的后面
-
不建议在 where 条件索引列上使用函数,会导致索引失效;开发时应考虑,实在无法避免时可使用函数索引
-
仅当like模糊匹配首位不是%时才能用上索引,仅在like模糊匹配有确定的前缀时并且前缀匹配的结果在表中占比较少是才需考虑创建索引
【隐式转换】
-
字符串和数字进行比对时,优化器会自动将字符串强制转换成数字后进行比对,无法使用到索引;注意字段类型必须匹配,防止隐式转换带来损耗;可以对传入的参数进行类型转换,但不能对列做类型转换;