Yhzhtk / note

知识代码笔记
https://github.com/Yhzhtk/note/issues
MIT License
108 stars 11 forks source link

Innodb 不同编码集、类型、长度的表,join 时能否用上索引? #43

Open Yhzhtk opened 8 years ago

Yhzhtk commented 8 years ago

问题

我们知道 utf8mb4 是向后兼容 utf8 字符集的,也就是说 utf8mb4 完全包含 utf8。

那么使用 utf8mb4、utf8 字符集的不同表,在 join 时能否用上索引,left join 顺序改变是否能改变结果呢?

如果关联字段的类型和编码集一样,不同的长度能否使用上索引呢?

如果关联字段的编码集一样,不同的类型能否使用上索引呢?

分析

下面通过学生表、班级表的例子来

DDL 如下:

// 班级表
CREATE TABLE `clazz` (
  `id` int(11) NOT NULL,
  `class` varchar(10) DEFAULT NULL,
  `class_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

// 学生表
CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `class` varchar(10) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_class` (`class`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

SQL 查询语句:

explain select * from clazz left join student on student.class = clazz.class;

实验结果

不同编码集能否使用索引

clazz.class | student.class | 能否使用索引
utf8        | utf8          | 能
utf8mb4     | utf8mb4       | 能
utf8        | utf8mb4       | 能
utf8mb4     | utf8          | 不能

不同长度能否使用索引

clazz.class | student.class | 能否使用索引
10          | 10            | 能
10          | 5             | 能
5           | 10            | 能

不同类型能否使用索引

clazz.class | student.class | 能否使用索引
char        | varchar       | 能
varchar     | char          | 能
varchar     | int           | 能
int         | varchar       | 不能

结论

  1. 编码集、类型、长度一样的情况下,能使用索引(毫无疑问)
  2. 用 utf8 去 left join utf8mb4 表字段的时候,能使用上索引,反过来用 utf8mb4 去 left join utf8 则不能使用上索引。这比较好理解, utf8mb4 兼容 utf8 嘛,所以,utf8 的任何一个字段,都能匹配上 utf8mb4
  3. 相同类型、不同长度的 join,都能使用上索引
  4. char、varchar 之间的 join,都能使用上索引
  5. varchar 去 left join int 时,能使用上索引,而 int left join varchar 则不能。勉强理解为, varchar 存储的二进制可以当场一个数字,而 int 存储的数字不能转成一个 varchar,所以不能

个人见解,如果有分析不正确的地方,欢迎指出交流!