Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ CALL pre_test1();

根据官方文档的描述,我们的第 23 两条 SQL 都发生了隐式转换,第 2 条 SQL 的查询条件`num1 = '10000'`,左边是`int`类型右边是字符串,第 3 条 SQL 相反,那么根据官方转换规则第 7 条,左右两边都会转换为浮点数再进行比较。

先看第 2 条 SQL:`SELECT * FROM`test1`WHERE num1 = '10000';` **左边为 int 类型**`10000`,转换为浮点数还是`10000`,右边字符串类型`'10000'`,转换为浮点数也是`10000`。两边的转换结果都是唯一确定的,所以不影响使用索引。
先看第 2 条 SQL:``SELECT * FROM `test1` WHERE num1 = '10000';`` **左边为 int 类型**`10000`,转换为浮点数还是`10000`,右边字符串类型`'10000'`,转换为浮点数也是`10000`。两边的转换结果都是唯一确定的,所以不影响使用索引。

第 3 条 SQL:`SELECT * FROM`test1`WHERE num2 = 10000;` **左边是字符串类型**`'10000'`,转浮点数为 10000 是唯一的,右边`int`类型`10000`转换结果也是唯一的。但是,因为左边是检索条件,`'10000'`转到`10000`虽然是唯一,但是其他字符串也可以转换为`10000`,比如`'10000a'`,`'010000'`,`'10000'`等等都能转为浮点数`10000`,这样的情况下,是不能用到索引的。
第 3 条 SQL:``SELECT * FROM `test1` WHERE num2 = 10000;`` **左边是字符串类型**`'10000'`,转浮点数为 10000 是唯一的,右边`int`类型`10000`转换结果也是唯一的。但是,因为左边是检索条件,`'10000'`转到`10000`虽然是唯一,但是其他字符串也可以转换为`10000`,比如`'10000a'`,`'010000'`,`'10000'`等等都能转为浮点数`10000`,这样的情况下,是不能用到索引的。

关于这个**隐式转换**我们可以通过查询测试验证一下,先插入几条数据,其中`num2='10000a'`、`'010000'`和`'10000'`:

Expand All @@ -129,7 +129,7 @@ INSERT INTO `test1` (`id`, `num1`, `num2`, `type1`, `type2`, `str1`, `str2`) VAL
INSERT INTO `test1` (`id`, `num1`, `num2`, `type1`, `type2`, `str1`, `str2`) VALUES ('10000003', '10000', ' 10000', '0', '0', '2df3d9465ty2e4hd523', '2df3d9465ty2e4hd523');
```

然后使用第三条 SQL 语句`SELECT * FROM`test1`WHERE num2 = 10000;`进行查询:
然后使用第三条 SQL 语句``SELECT * FROM `test1` WHERE num2 = 10000;``进行查询:

![](https://oss.javaguide.cn/github/javaguide/mysqlindex-invalidation-caused-by-implicit-conversion-03.png)

Expand All @@ -144,7 +144,7 @@ INSERT INTO `test1` (`id`, `num1`, `num2`, `type1`, `type2`, `str1`, `str2`) VAL

如此也就印证了之前的查询结果了。

再次写一条 SQL 查询 str1 字段:`SELECT * FROM`test1`WHERE str1 = 1234;`
再次写一条 SQL 查询 str1 字段:``SELECT * FROM `test1` WHERE str1 = 1234;``

![](https://oss.javaguide.cn/github/javaguide/mysqlindex-invalidation-caused-by-implicit-conversion-05.png)

Expand All @@ -159,4 +159,4 @@ INSERT INTO `test1` (`id`, `num1`, `num2`, `type1`, `type2`, `str1`, `str2`) VAL

所以,我们在写 SQL 时一定要养成良好的习惯,查询的字段是什么类型,等号右边的条件就写成对应的类型。特别当查询的字段是字符串时,等号右边的条件一定要用引号引起来标明这是一个字符串,否则会造成索引失效触发全表扫描。

<!-- @include: @article-footer.snippet.md -->
<!-- @include: @article-footer.snippet.md -->
5 changes: 3 additions & 2 deletions docs/database/mysql/mysql-query-execution-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ id 如果相同,从上往下依次执行。id 不同,id 值越大,执行
查询用到的表名,每行都有对应的表名,表名除了正常的表之外,也可能是以下列出的值:

- **`<unionM,N>`** : 本行引用了 id 为 M 和 N 的行的 UNION 结果;
- **`<derivedN>`** : 本行引用了 id 为 N 的表所产生的的派生表结果。派生表有可能产生自 FROM 语句中的子查询。 -**`<subqueryN>`** : 本行引用了 id 为 N 的表所产生的的物化子查询结果。
- **`<derivedN>`** : 本行引用了 id 为 N 的表所产生的的派生表结果。派生表有可能产生自 FROM 语句中的子查询。
- **`<subqueryN>`** : 本行引用了 id 为 N 的表所产生的的物化子查询结果。

### type(重要)

Expand Down Expand Up @@ -140,4 +141,4 @@ rows 列表示根据表统计信息及选用情况,大致估算出找到所需
- https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
- https://juejin.cn/post/6953444668973514789

<!-- @include: @article-footer.snippet.md -->
<!-- @include: @article-footer.snippet.md -->