学海无涯,旅“途”漫漫,“途”中小记,如有错误,敬请指出,在此拜谢!
文章目录
- 前言
- 函数错误
- concat函数使用有区别
- 代码示例
- 导致问题
- 区别及分析
- 解决方法
- 时间相减
- 代码示例
- 导致问题
- 区别与分析
- 解决方法
- or 不走索引
- 代码示例
- 导致问题
- 区别与分析
- oracle
- mysql
- 解决办法
- 其他错误
- 转换时,oracle类型Number类型对应到mysql为decimal
前言
最近有幸,我司的一个项目在进行oracle转mysql数据库,其中碰到了一些坑,排查发现了一些共性问题,遂记录当前文档进行处理。为了不出现公司的相关内容,部分图片会添加马赛克,进行模糊处理,如有不清楚的地方,可以私聊讨论,对应的版本内容如下:
工具 | 对应版本 |
---|---|
Oracle | 12c |
Mysql | 8.0.33 |
ORM框架 | mybatis 3.4.2 |
转换工具 | Navicat |
函数错误
concat函数使用有区别
代码示例
select concat(字段A,字段B) from 表名;
导致问题
查出的数据为空
区别及分析
区别 | Oracle | Mysql |
---|---|---|
拼接内容 | 只能拼接两个字符串CONCAT(str1,str2) | 能拼接多个CONCAT(str1,str2,…) |
参数为空结果 | 有空值也没事(下图1) | 只要有一个为空,结果就是空(下图2) |
解决方法
在mysql中,增加ifnull(参数,‘’)的函数,保证如果参数为空,则返回空字符串即可
时间相减
代码示例
select REALEND(时间字段1) - REALSTART(时间字段2) from 表 where;
导致问题
数据计算出错
区别与分析
区别 | Oracle | Mysql |
---|---|---|
时间相减 | 计算出是以天为单位的数字 | 计算出的结果很怪异 |
oracle Date减出来的是以天为单位
mysql datetime减出来的,很奇怪。
解决方法
需要增加time_to_sec,求出的是秒数。如果要转日或者天,则除以60和24即可。
or 不走索引
代码示例
select c.ID,g.realstart,row_number() OVER (PARTITION BY c.id,cd.name ORDER BY g.realstart ,g.字段a) AS d
FROM 表c c
left join 表f f on c.aid = f.ID or c.did = f.ID
left join 表g g on f.ID = g.fid and g.realstart is not null
left join 表cd cd ON g.did = cd.id
WHERE c.create_time BETWEEN '2023-07-06' AND '2023-07-13';
导致问题
不走索引会出现查询缓慢
区别与分析
oracle
oracle的or语法走不走索引,这个还不一定,最好自己在写完sql后,自己查询一下执行计划,看看扫描行数。使用plsql的功能可以查询,我使用的是datagrip,选择要查询的sql,右键会出现explain plan的按钮,点击便可以查看。
点击之后结果如下所示,可以看出,扫描最多的行数为3360,明显不是全表扫描(这几个表,每个表都至少5W+的数据量)
mysql
mysql使用explain即可,可以查询扫描结果。结果如下图所示,可以看出,第二条数据,扫描了40W行数据,进行了一次全表扫描
解决办法
将or转换成union all,每个链接子查询都走索引,速度就很快了
select ID,realstart,row_number() OVER (PARTITION BY id,name ORDER BY realstart ,d) AS dr
from (select c.ID,g.realstart,name,g.d
FROM 表c c
left join 表f f on c.aid = f.ID
left join 表g g on f.ID = g.fid and g.realstart is not null
left join 表cd cd ON g.dispatchid = cd.id
WHERE c.create_time BETWEEN '2023-07-06' AND '2023-07-13'
union all
select c.ID,g.realstart,name, g.d
FROM 表c c
left join 表f f on c.did = f.ID
left join 表g g on f.ID = g.fid and g.realstart is not null
left join 表cd cd ON g.dispatchid = cd.id
WHERE c.create_time BETWEEN '2023-07-06' AND '2023-07-13') as kkt1
如图所示可以看出,每个执行的sql,扫描行数的极少
在修改完之后,总体sql(以上查询的sql,只为总sql的一小部分)查询时间从27秒减小到526毫秒。优化效果显著。
其他错误
转换时,oracle类型Number类型对应到mysql为decimal
在oracle中,经常会用Number作为数字类型的存储,Number默认值,可以认为Number(38,0),最后存储的是一个整数,而转换到mysql上,就会变成decimal(65,32),导致查询的时候出现一堆小数点的问题。