-
DELETE 【规格】不支持DELETE语句中使用LIMIT。应使用WHERE条件明确需要更新的目标行。 【规格】在GTM-FREE模式下,不允许跨节点事务,因此删除HASH分布表中数据时,必须在WHERE条件中指定分布列等值过滤条件。 【规格】不支持多表删除。 多表删除即在单条SQL语句中,对多个表进行删除。 【规则】DELETE语句中必须有WHERE子句,避免全表扫描。 【规则】DELETE语句中禁止使用ORDER BY、GROUP BY子句,避免不必要的排序。 【规则】如果需要清空一张表,建议使用TRUNCATE,而不是DELETE。 TRUNCATE会创建新的物理文件,并在事务结束时将原文件物理删除,清空磁盘空间。而DELETE会将表中数据进行标记,直到VACUUM FULL阶段才会真正清理磁盘空间。 【建议】DELETE有主键或索引的表,WHERE条件应结合主键或索引,提高执行效率。 父主题: 数据库编程规范
-
INSERT 【规格】INSERT ON DUPLICATE KEY UPDATE不支持对主键或唯一约束的列上执行UPDATE。 INSERT ON DUPLICATE KEY UPDATE的语义是对唯一约束冲突的行进行更新,这个过程中不应对约束的值进行更新。 【规则】禁止对存在多个唯一约束的表执行INSERT ON DUPLICATE KEY UPDATE。 表中存在多个唯一约束包括存在多个唯一索引,或既存在主键(PRIMARY KEY),又存在唯一索引(UNIQUE INDEX)两种情况。当存在多个唯一约束时,会默认检查所有的唯一约束条件,只要任何一个约束存在冲突,就会对冲突行进行更新,即可能更新多条记录,与业务预期不相符。业务应给予更加明确的插入更新条件。 【建议】对于批量插入的情况,建议使用executeBatch执行INSERT INTO VALUES (?),执行效率将高于执行多条INSERT INTO VALUES(?)或INSERT INTO VALUES(?),...,(?)。 父主题: 数据库编程规范
-
INSERT 【规格】INSERT ON DUPLICATE KEY UPDATE不支持对主键或唯一约束的列上执行UPDATE。 INSERT ON DUPLICATE KEY UPDATE的语义是对唯一约束冲突的行进行更新,这个过程中不应对约束的值进行更新。 【规则】禁止对存在多个唯一约束的表执行INSERT ON DUPLICATE KEY UPDATE。 表中存在多个唯一约束包括存在多个唯一索引,或既存在主键(PRIMARY KEY),又存在唯一索引(UNQUE INDEX)两种情况。当存在多个唯一约束时,会默认检查所有的唯一约束条件,只要任何一个约束存在冲突,就会对冲突行进行更新,即可能更新多条记录,与业务预期不相符。业务应给予更加明确的插入更新条件。 【建议】对于批量插入的情况,建议使用executeBatch执行INSERT INTO VALUES (?),执行效率将高于执行多条INSERT INTO VALUES(?)或INSERT INTO VALUES(?),...,(?)。 父主题: 数据库编程规范
-
对象访问编程规范 【规则】用户在操作对象时,应该拥有该对象的操作权限。 权限说明请参考用户及权限章节,并遵循权限设计规范。 【规则】访问对象(表,函数等)时建议带上SCHEMA名称,即使用schemaname.tablename进行访问。 如果不追加SCHEMA名称前缀,会根据当前search_path中表空间列表,依次搜索所有表空间直到找到匹配的表,造成不必要的性能开销。 父主题: 数据库编程规范
-
DELETE 【规则】DELETE语句中必须有WHERE子句,避免全表扫描。 【规则】DELETE语句中禁止使用ORDER BY、GROUP BY子句,避免不必要的排序。 【规则】如果需要清空一张表,建议使用TRUNCATE,而不是DELETE。 TRUNCATE会创建新的物理文件,并在事务结束时将原文件物理删除,清空磁盘空间。而DELETE会将表中数据进行标记,直到VACUUM FULL阶段才会真正清理磁盘空间。 【建议】DELETE有主键或索引的表,WHERE条件应结合主键或索引,提高执行效率。 父主题: 数据库编程规范
-
GUC参数编程规范 【规则】客户端(如JDBC)应使用默认参数执行查询,如果需要修改会话级别的GUC参数,应谨慎评估。 通过ODBC或JDBC修改GUC参数时,需注意GUC参数仅会在当前connection中生效,特别是在连接池场景下,容易出现问题且问题定位困难。 如果在连接中必须进行GUC参数设置,那么在将连接归还给连接池之前,必须使用 SET SESSION AUTHORIZATION DEFAULT;RESET ALL; 将连接的状态清空。 父主题: 数据库编程规范
-
数据加载和卸载 在INSERT语句中显式设置插入的字段列表。例如: 1 INSERT INTO task(name,id,comment) VALUES ('task1','100','第100个任务');
在批量数据入库之后,或者数据增量达到一定阈值后,建议对表进行ANALYZE操作,防止统计信息不准确而导致的执行计划劣化。 如果要清理表中的所有数据,建议使用TRUNCATE TABLE方式,不要使用DELETE TABLE方式。DELETE TABLE方式删除性能差,且不会释放那些已经删除了的数据占用的磁盘空间。
-
DDL 在
GaussDB 中,建议DDL(建表、COMMENT等)操作统一执行。在批处理作业中尽量避免DDL操作,避免大量并发事务对性能的影响。 在非日志表(unlogged table)使用完后,立即执行数据清理(TRUNCATE)操作。因为在异常场景下,GaussDB不保证非日志表(unlogged table)数据的安全性。 临时表和非日志表的存储方式建议和基表相同。 索引字段的总长度不超过50字节。否则,索引大小会膨胀比较严重,带来较大的存储开销,同时索引性能也会下降。 不要使用DROP…CASCADE方式删除对象,除非已经明确对象间的依赖关系,以免误删。
-
DDL 【规则】禁止在业务高峰期执行DDL操作。若必须执行DDL,应控制DDL的执行频率(每秒不超过1次DDL操作)。 DDL对象的锁使用全局常规锁表进行管理。DDL操作会对常规锁表的访问形成竞争,导致大量线程在LockMgrLock等待事件中被阻塞,存在线程池资源耗尽的风险,可能会引发主备切换或触发GaussDB线程池抗过载机制,从而影响业务成功率。 DDL操作需要失效对象的系统表缓存,以便其他并发线程能够感知DDL对象的变化。且其他线程需要处理失效消息,这会增加线程处理压力,存在CPU升高的风险。 DDL日志的回放速度远慢于DML日志的回放。频繁DDL操作可能导致主备时延增大,引发流控。因此,建议在业务高峰期控制DDL频率,避免触发流控。 【规则】禁止在同一个事务内执行DDL与其他业务操作,DDL应在独立事务内执行。 父主题: 数据库编程规范
-
UPDATE 【规则】UPDATE语句中必须有WHERE子句,避免全表扫描。 【规则】不允许在UPDATE子句同时更新多个列时,被更新列同样是更新源。 同时更新多列,且更新源相同,在不同的数据库下行为不同,为了避免带来兼容性问题,业务层应避免上述操作。示例如下: UPDATE table SET col1 = col2, col3 = col1 WHERE col1 = 1; 该语句在中,col3的值为原col1的值;而MySQL中,col3的值为col2的值(因为col2的值被赋予给了col1)。 【规则】UPDATE语句中禁止使用ORDER BY、GROUP BY子句,避免不必要的排序。 【建议】有主键/索引的表,更新时WHERE条件应结合主键/索引。 父主题: 数据库编程规范
-
SELECT 【规则】SELECT语句中禁用通配符字段“*”。 使用通配符字段查询表时,如果因业务或数据库升级导致表结构发生变化,可能出现与业务语句不兼容的情况。因此业务应指明所需查询的表字段名称,避免使用通配符。 【规则】避免对大字段(如VARCHAR(2000))执行ORDER BY、DISTINCT、GROUP BY、UNION等会引起排序的操作。 此类操作将消耗大量的CPU和内存资源,执行效率低下。 【规则】禁止使用LOCK TABLE语句加锁,仅允许使用 SELECT .. FOR UPDATE语句。 LOCK TABLE提供多种锁级别,但如果对数据库原理和业务理解不足,误用表锁可能触发死锁,导致数据库不可用。 【建议】考虑使用UNION ALL,少使用UNION,注意考虑去重。 UNION ALL不去重,少了排序操作,速度相对UNION更快。如果没有去重的需求,优先使用UNION ALL。 【建议】避免频繁使用count()获取大表行数,该操作资源消耗较大,影响并行作业执行效率。 如果不需要实时的行数统计信息,可以尝试使用如下语句来获取表行数。 SELECT reltules FROM pg_class WHERE relname = 'tablename'; pg_class中所记录的表行数信息只会在对该表执行ANALYZE以后才会更新。 目前ANALYZE有两种触发条件: 业务主动发送ANALYZE语句,例如: --分析连接库中所有表
ANALYZE;--分析指定表ANALYZE tablename; 借助AUTO VACUUM机制,在每间隔一定时间或表的增删达到一定行数时触发。间隔时间和增删比例可通过GUC参数设置。 父主题: 数据库编程规范
-
关联查询 【规则】多表关联嵌套深度必须小于8。 关联嵌套过深,容易产生慢SQL,应从业务层考虑优化。 【规则】表关联查询必须明确指定各表的连接条件(ON),以避免产生笛卡尔积。 例如在MySQL中,JOIN与CROSS JOIN和INNER JOIN等价,但是在SQL标准中,JOIN仅与INNER JOIN等价,必须配合使用ON连接条件。 【规则】关联时,应该根据SQL标准指明连接方式,避免直接使用JOIN关键词,而是使用CROSS JOIN、INNER JOIN、LEFT JOIN、RIGHT JOIN等。 【规则】多表关联查询时, 必须对表添加使用别名,保证语句逻辑清晰,便于维护。 【建议】不同字段的比较开销不同,关联字段应尽量使用比较效率高的字段类型。 数值类型的比较效率远高于字符串类型。 在数值类型中,整型效率高于NUMERIC和浮点类型。 【建议】关联字段应为相同数据类型,避免存在隐式类型转换影响执行效率。 【建议】少用嵌套子查询,尽量使用表关联,因为子查询会产生临时表,对SQL性能影响较大。 【建议】对于关联列上存在大量NULL值的情况,建议在WHERE条件中增加关联列IS NOT NULL的过滤条件,能够提升执行效率。 父主题: 数据库编程规范
-
子查询 【规则】禁止一条SQL语句中,出现重复子查询语句。 【建议】少用标量子查询。 标量子查询指结果为一个值,并且条件表达式为等值的子查询。 示例: 不符合规范的语句 SELECT * FROM t1 WHERE id = (SELECT id FROM t2 LIMIT 1); 上述语句建议业务拆分为两条SQL语句,先执行子查询。 【建议】避免在SELECT目标列中使用子查询,可能导致计划无法下推影响执行性能。 【建议】子查询嵌套深度不建议超过两层。 由于子查询会带来临时表开销,过于复杂的查询应考虑从业务逻辑上进行优化。 父主题: 数据库编程规范
-
SELECT 【规则】SELECT语句中禁用通配符字段“*”。 使用通配符字段查询表时,如果因业务或数据库升级导致表结构发生变化,可能出现与业务语句不兼容的情况。因此业务应指明所需查询的表字段名称,避免使用通配符。 【规则】带有LIMIT的查询语句中必须带有ORDER BY保证有序。 作为一种
分布式数据库 ,表数据将分布在多个DN上。如果SQL语句中只带有LIMIT,而不带有ORDER BY子句,数据库将会把网络传输较快的DN所发送的(符合查询要求的)结果作为最终结果输出到客户端。由于网络传输效率不同时刻可能发生改变,因此导致多次执行该SQL语句时,返回结果表现出不一致的情况。 【规则】避免对大字段(如VARCHAR(2000))执行ORDER BY、DISTINCT、GROUP BY、UNION等会引起排序的操作。 此类操作将消耗大量的CPU和内存资源,执行效率低下。 【规则】禁止使用LOCK TABLE语句加锁,仅允许使用 SELECT .. FOR UPDATE语句。 LOCK TABLE提供多种锁级别,但如果对数据库原理和业务理解不足,误用表锁可能触发死锁,导致集群不可用。 【建议】避免在SELECT目标列中使用子查询,可能导致计划无法下推到DN执行,影响执行性能。 【建议】考虑使用UNION ALL,少使用UNION,注意考虑去重。 UNION ALL不去重,少了排序操作,速度相对UNION更快。如果没有去重的需求,优先使用UNION ALL。 【建议】避免频繁使用count()获取大表行数,该操作资源消耗较大,影响并行作业执行效率。 如果不需要实时的行数统计信息,可以尝试使用如下语句来获取表行数。 SELECT reltules FROM pg_class WHERE relname = 'tablename'; pg_class中所记录的表行数信息只在对该表执行ANALYZE以后才会更新。 目前ANALYZE有两种触发条件: 业务主动发送ANALYZE语句,例如: --分析连接库中所有表
ANALYZE;
--分析指定表
ANALYZE tablename; 借助AUTO VACUUM机制,在每间隔一定时间或表的增删达到一定行数时触发。间隔时间和增删比例可通过GUC参数设置。 父主题: 数据库编程规范
-
对象访问编程规范 【规则】用户在操作对象时,应该拥有该对象的操作权限。 权限说明请参考用户及权限章节,并遵循权限设计规范。 【规则】访问对象(表,函数等)时建议带上SCHEMA名称,即使用schemaname.tablename进行访问。 如果不追加SCHEMA名称前缀,会根据当前search_path中表空间列表,依次搜索所有表空间直到找到匹配的表,这会带来不必要的性能开销。 父主题: 数据库编程规范