1. 概述
2. 判断是读取慢还是写入慢
2.1 任务正在执行
1)先终止该定时任务的执行。
将该定时任务的日志等级设置为 INFO,用于记录定时任务的读写明细。保存之后重启一下任务,开始记录。

2)执行一段时间后,下载日志开始分析。

3)根据用户查询与输出的 SQL 定位任务日志的位置。

从上面的截图我们可以看出需要该任务对应的任务名称是job[22]。然后我们往下翻,能看到job[22]任务的读写情况。

数据来源代表表输入、数据去向代表表输出。因为我们的同步过程是流式的,所以可以看到一个任务拆成了多个读取与写入。
然后看后面的 waittime。数据来源的 waittime 代表目前在等待数据完成写入,数据去向的 waittime 代表目前正在等待数据完成读取。哪个时间大,说明在等待另一个线程完成对应的任务。
从上面我们可以看出数据来源的时间比数据去向大很多,说明当前任务卡在了数据写入的状态下。
因此我们需要进一步排查。
2.2 任务执行完毕
直接看历史运维记录的统计,看是输入还是输出慢。

3. 读取慢排查步骤
选择一张有一定数据量(数据量过大可以截取 3W 数据)的简单表进行数据同步,等运行结束之后查看表输入带宽。如果带宽在3~4MB/s,说明读取带宽没有问题。

如果带宽较小,则需要沟通是否可以切换内网忽略带宽问题或者增加公网的带宽。
2)使用并行取数针对数据基数较大的表,可能初始读取速度会较慢。表现现象为输入、输出0行/s的等待时间稍微有点长。
此时我们可以使用 并行读取 功能,通过切分键将数据拆成多个同步任务。降低部分步骤初始等待时间。
3)是否因为数据库锁,导致查询不返回通过查询 SQL 运行状态,查看是否被数据库锁住(locaked)。根据锁的类型判断如何进行优化。
4)优化 SQL 语句| 优化SQL | 说明 |
|---|---|
| 对过滤字段增加索引 | 通过对 Where 字段增加索引的方式,加快速度读取 索引查询从最左侧的索引列开始,避免跳过中间的索引列 范围查询放到最后 |
| SELECT 子句中避免使用 “*” | 当你想在 SELECT 子句中列出所有的 columns 时,使用动态 SQL 列引用‘*’是一个方便的方法 不幸的是,这是一个非常低效的方法。 实际上,Oracle 在解析的过程中, 会将“*” 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间 |
| left join小表在前 | 把重复关联键少的表放在 join 前面做关联可以提高 join 的效率 |
| 计算记录条数 | 和一般的观点相反count(*) 比count(1)稍快,当然如果可以通过索引检索,对索引列的计数仍旧是最快的。例如 COUNT(EMPNO) |
| 删除重复记录(使用了 ROWID) | DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO) |
| 用 TRUNCATE 替代 DELETE | 当删除表中的记录时,在通常情况下,回滚段(rollback segments)用来存放可以被恢复的信息。如果你没有 COMMIT 事务,Oracle 会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况),而当运用 TRUNCATE 时, 回滚段不再存放任何可被恢复的信息。当命令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短 |
| 用 >= 替代 > | 例如 DEPTNO 上有一个索引: 高效: SELECT * FROM EMP WHERE DEPTNO >=4 低效: SELECT * FROM EMP WHERE DEPTNO >3 |
| 用 EXISTS 替代 IN | 在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。在这种情况下,使用 EXISTS 或 NOT EXISTS 可以提高查询的效率。例如: 低效: SELECT * FROM EMP WHERE EMPNO > 0 AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC ='MELB') 高效: SELECT * FROM EMP WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = 'MELB') |
| 用 EXISTS 替换 DISTINCT | 当提交一个包含一对多表信息( 比如部门表和雇员表 )的查询时,避免在 SELECT 子句中使用 DISTINCT, 一般可以考虑用 EXIST 替换。例如: 低效: SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D,EMP E WHERE D.DEPT_NO = E.DEPT_NO 高效: SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X’ FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO) |
| 应尽量避免在 where 子句中对字段判断 | 例如: select id from t where num is null 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询: select id from t where num=0 |
| 应避免在 where 中使用 != 或 <> 操作符 | 将引擎放弃使用索引而进行全表扫描。优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。 |
| 应避免在 where 子句中使用 or 连接 | 否则将导致引擎放弃使用索引而进行全表扫描,例如: select id from t where num=10 or num=20 可以这样查询: select id from t where num=10 union all select id from t where num=20 |
| in 和 not in 也要慎用 | 因为 IN 会使系统无法使用索引,而只能直接搜索表中的数据。例如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3 |
| 应避免在 where 中进行表达式操作 | 这将导致引擎放弃使用索引而进行全表扫描。例如:
注:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。 |
| 应避免在 where 子句中进行函数操作 | 这将导致引擎放弃使用索引而进行全表扫描。例如:
|
| 不要在 where 中的“=”左边运算 | 进行函数、算术运算或其他表达式运算,系统将可能无法正确使用索引。 |
| 充分利用连接条件 | 在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将连接条件完整的写上,有可能大大提高查询速度。例如: SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO 第二句将比第一句执行快得多 |
| 能用 GROUP BY 就不用 DISTINCT | SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10 可改为: SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID |
| 能用 UNION ALL 就不要用 UNION | UNION ALL 不执行 SELECT DISTINCT 函数,这样就会减少很多不必要的资源 |
| 尽量不要用 SELECT INTO 语句 | SELECT INTO 语句会导致表锁定,阻止其他用户访问该表 |
5)测试是否为驱动问题
在驱动网站查找较高或者较低版本的数据库驱动,测试读取速度。
6)是否为数据库自身问题
Greenplum 可能会有系统或者业务表膨胀问题导致读取速度越使用越慢,需要定期处理业务表膨胀。
7)测试是否为FDL问题
使用服务器数据集,通过数据集输入测试读取速度。
8)还是排查不出原因,找技术支持协助或社区问答进行协助。
4. 写入慢排查步骤
1)上行带宽
选择一张有一定数据量(数据量过大可以截取3W数据)的简单表使用自动建表无主键方式进行写入,测试写入带宽是否在3~4MB/s。
2)数据库主键
整体数据同步速率:无物理主键+直接写入>大数据量的数据比对更新(个别数据库逻辑可能不符,比如sr、doris)~中等数据量的物理主键直接覆盖>逻辑主键直接覆盖
所以有时可将逻辑主键修改为物理主键,或者新增物理主键,写入速度会提升。
主键设置不合理。select count(*) from 来源表与目标表数量不匹配。
select 主键字段,count(*) from (select count(*) from 来源表) a group by 主键字段,发现按照主键字段数据不唯一。说明来源端的数据在写入目标表时,一直在按照主键进行数据覆盖。如果来源表数据量很大的话,会导致写入速度非常慢。
3)数据写入方式
使用清空导入并且存在物理主键时,也会按照上面自己覆盖自己的方式进行数据写入导致速度很慢。
4)写入语句锁表
当触发表级锁或者行级锁,或者清空写入执行 truncate 被锁表时,会导致写入速度非常慢。
5)数据库特性
Clickhouse 主键更新慢,建议使用数据比对更新。
6)是否为数据库自身问题
Greenplum 可能会有系统或者业务表膨胀问题导致写入速度越使用越慢,需要定期处理业务表膨胀。
