【问题标题】:mysql: index on json array not used when joining another tablemysql:加入另一个表时未使用json数组上的索引
【发布时间】:2021-11-21 02:56:28
【问题描述】:

我有 2 张桌子:

CREATE TABLE `directory` (
  `id` bigint NOT NULL,
  `datasets` json DEFAULT NULL
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_datasets` ((cast(`datasets` as unsigned array)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `dataset` (
  `id` bigint NOT NULL,
  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_name` (`name`,`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

下面的查询按预期使用了两个表上的索引:

explain
SELECT * FROM dataset d inner join `directory` dir
on JSON_CONTAINS(dir.datasets, cast(d.id as json))
where d.id = 111;
id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  d       const   PRIMARY PRIMARY 8   const   1   100.00  
1   SIMPLE  dir     range   idx_datasets    idx_datasets    9       2   100.00  Using where

但是,这个查询只在左表上使用索引

explain
SELECT * FROM dataset d inner join `directory` dir
on JSON_CONTAINS(dir.datasets, cast(d.id as json))
where d.name like '111';
id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  d       range   idx_name    idx_name    259     1   100.00  Using index condition
1   SIMPLE  dir     ALL                 1000    100.00  Using where; Using join buffer (hash join)

有人能解释一下这两个查询的区别吗?


我把条件“like”改成“=”,结果是一样的:

explain
SELECT * FROM dataset d inner join catalog dir
on JSON_CONTAINS(dir.datasets, cast(d.id as json))
where d.name = '111';
id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  d       ref idx_name    idx_name    259 const   1   100.00  
1   SIMPLE  dir     ALL                 1000    100.00  Using where; Using join buffer (hash join)

【问题讨论】:

  • d.name like '111' 只会找到'111'。没有通配符的 LIKE 没有意义,必须替换为 =
  • @Akina 仅用于演示,替换“like”不会导致在右表上使用索引。
  • d.id 是主键,而 d.name 不是。这可能是原因

标签: mysql json join indexing


【解决方案1】:

这是由第二个查询中WHERE 子句中的like 表达式引起的

这就是为什么,在一些线程中解释: 1-Equals(=) vs. LIKE 2-SQL 'like' vs '=' performance

EDIT 看起来这里的问题是由于在第一个查询中您正在搜索主键,而在第二个查询中您没有

这个问题的更多细节: Behavior of WHERE clause on a primary key field

【讨论】:

  • 其实在两个查询中,左表都使用了索引,这里使用了“like”。如果我将“like”更改为“=”,结果是一样的。
猜你喜欢
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 2020-07-28
  • 2014-11-04
  • 2013-07-30
  • 2015-09-01
  • 2021-11-24
  • 2023-01-13
相关资源
最近更新 更多