0
点赞
收藏
分享

微信扫一扫

转载:在左表或右表的连接字段上建立索引对左、内连接的查询效率的优化情况分析

萨科潘 2022-03-11 阅读 49
mysql

转载于:地址

1、建表

DROP TABLE
IF EXISTS dept_tbl;

CREATE TABLE dept_tbl (
	rcrd_id INT UNSIGNED PRIMARY KEY auto_increment COMMENT '记录编号',
	dept_id INT UNSIGNED NOT NULL COMMENT '部门编号'
) ENGINE = INNODB DEFAULT charset = utf8 COMMENT '部门表';


DROP TABLE
IF EXISTS emp_tbl;

CREATE TABLE emp_tbl (
	rcrd_id INT UNSIGNED PRIMARY KEY auto_increment COMMENT '记录编号',
	emp_id INT UNSIGNED NOT NULL COMMENT '员工编号',
	dept_id INT UNSIGNED COMMENT '部门编号'
) ENGINE = INNODB DEFAULT charset = utf8 COMMENT '员工表';

– 2、造数据;

insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
insert into dept_tbl(dept_id) values (floor(1+(rand()*20)));
 
 
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));
 
insert into emp_tbl(emp_id, dept_id) values (floor(1+(rand()*10000)), floor(1+(rand()*50)));

– 3、查看索引

– 4、左连接

– 4.1、在左右表的连接字段 dept_id 上均未建索引的情况下,测试其扫描类型 type 和扫描行数 rows

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
LEFT JOIN emp_tbl b ON a.dept_id = b.dept_id

**-- 【结论 4.1】 在左右表的连接字段 dept_id 上均未建索引的情况下:**左连接使用全表扫描的方式查询左右表;

– 4.2、仅在左表连接字段 dept_id 上建索引,测试左连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl ADD KEY `idx_dept_id` (`dept_id`);
 
EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
LEFT JOIN emp_tbl b ON a.dept_id = b.dept_id;

–【结论 4.2】仅在左表连接字段 dept_id 上建索引: a 表使用了覆盖索引扫描,但扫描行数没变,查询效率得到优化;b 表使用了全表扫描,且扫描行数没变,查询效率未得到优化;

– 4.3、仅在右表连接字段 dept_id 上建索引,测试左连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl DROP KEY `idx_dept_id`;
 
ALTER TABLE emp_tbl ADD KEY `idx_dept_id` (`dept_id`);
 
EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
LEFT JOIN emp_tbl b ON a.dept_id = b.dept_id;

–【结论 4.3】仅在右表连接字段 dept_id 上建索引: 对右表 b 上的连接字段建立索引的查询效率优化情况如下:

a 表使用了全表扫描,扫描行数没变;b 表使用了非唯一性索引单值扫描 ref, 且扫描行数为 15;对 a 表的查询效率没有优化,但 b 表却优化了;

– 4.4、在左表和右表的连接字段 dept_id 上都建索引,测试左连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl ADD KEY `idx_dept_id` (`dept_id`);

ALTER TABLE emp_tbl ADD KEY `idx_dept_id` (`dept_id`);

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
LEFT JOIN emp_tbl b ON a.dept_id = b.dept_id;
 

– 【结论 4.4】在左表 a 和右表 b 的连接字段 dept_id 上都建索引后: a 表使用了覆盖索引扫描,但扫描行数没变;b 表使用了非唯一性索引单值扫描 ref,扫描行数减少,查询效率得到优化;

– 5、内连接

– 5.0 查看索引

– 5.1、在左右表的连接字段 dept_id 上均未建索引的情况下,测试其扫描类型 type 和扫描行数 rows

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
INNER JOIN emp_tbl b ON a.dept_id = b.dept_id;

**-- 【结论 5.1】在左右表上的连接字段均不建索引:**a 表使用了全表扫描,且总行数 100 条;b 表使用了全表扫描,其总行数 700 条,这时的查询效率最低;

– 5.2、仅在左表连接字段 dept_id 上建索引,测试内连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl ADD KEY `idx_dept_id` (`dept_id`);

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
INNER JOIN emp_tbl b ON a.dept_id = b.dept_id;

– 【结论 5.2】 仅在左表连接字段上建索引: a 表使用了覆盖索引扫描,扫描行数为 2 条,扫描行数减少;b 表使用了全表扫描,扫描行数 700 条,扫描行数没变;故在左表 a 的连接字段建立索引后,a 表的查询效率得到优化;

b 表的查询效率没有得到优化;

– 5.3、仅在右表 emp_tbl 的连接字段 dept_id 上建索引,测试内连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl DROP KEY `idx_dept_id`;

ALTER TABLE emp_tbl ADD KEY `idx_dept_id` (`dept_id`);

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id
FROM
	dept_tbl a
INNER JOIN emp_tbl b ON a.dept_id = b.dept_id;

– 【结论 5.3】仅在右表 emp_tbl,即 b 表的连接字段 dept_id 上建索引: a 表使用了全表扫描,扫描行数 100 条,查询效率未优化; b 表使用了非唯一性索引单值扫描,扫描行数 15 条,查询效率得到优化;故在右表 b 的连接字段建立索引后,a 表的查询效率没有得到优化;b 表的查询效率得到优化;

– 5.4、在左表和右表的连接字段上都建索引,测试内连接的扫描类型 type 和扫描行数 rows

ALTER TABLE dept_tbl ADD KEY `idx_dept_id` (`dept_id`);

ALTER TABLE emp_tbl ADD KEY `idx_dept_id` (`dept_id`);

EXPLAIN SELECT
	a.rcrd_id,
	a.dept_id AS a_dept_id,
	b.rcrd_id,
	b.emp_id,
	b.dept_id AS b_dept_id
FROM
	dept_tbl a
INNER JOIN emp_tbl b ON a.dept_id = b.dept_id;

– 【结论 5.4】 在左表和右表的连接字段上都建索引: 左表即 a 表使用了覆盖索引,扫描行数 100 条,查询效率得到优化; 右表即 b 表使用了非唯一性索引扫描,扫描行数 14 条,查询效率得到优化;

【总结论】

1、对于左连接:

  • 1.1、在左表和右表的连接字段上都不建立索引:左右表都是全表扫描,查询效率最低;
  • 1.2、仅在左表的连接字段上建立索引:左表使用了覆盖索引扫描,扫描行数没变,查询效率得到优化;b 表使用了全表扫描,且扫描行数没变,查询效率未得到优化;
  • 1.3、仅在右表连接字段上建索引: 左表表使用了全表扫描,扫描行数没变,查询效率未得到优化;右表使用了非唯一性索引单值扫描 ref,扫描行数减少,查询晓得得到优化;
  • 1.4、在左表和右表的连接字段上都建索引后: 左表使用了覆盖索引扫描,扫描行数没变,查询效率得到优化;右表使用了非唯一性索引单值扫描 ref,扫描行数减少,查询效率得到优化;

2、对于内连接

  • 2.1、在左表和右表的连接字段上都不建立索引:左右表都是全表扫描,查询效率最低;
  • 2.2、仅在左表的连接字段上建立索引: 左表使用了覆盖索引扫描,扫描行数减少,查询效率得到优化;右表使用了全表扫描,扫描行数没变,查询效率没有得到优化;
  • 2.3、仅在右表连接字段上建索引: 左表使用了全表扫描,扫描行数没变,查询效率未优化; 右表使用了非唯一性索引单值扫描,扫描行数减少,查询效率得到优化;
  • 2.4、在左表 a 和右表 b 的连接字段上都建索引后:左表使用了覆盖索引,扫描行数不变,查询效率得到优化;右表使用了非唯一性索引扫描,扫描行数减少,查询效率得到优化;

3、全文总结论:

【关于左连接的结论补充】

  • 补充 1:由于非唯一性索引单值扫描 ref 的查询效率高于索引扫描 index 的查询效率, 所以左连接建议优先在右表的连接字段添加索引,当然最好是左表也加上;
  • 补充 2:还有一个本质问题是左连接时左表是主表,无论右表如何,左表的记录都会出现在查询结果中,即无论索引怎么建立,都要遍历左表的所有记录行数;
举报

相关推荐

0 条评论