前几天,小伙伴们在群里面讨论进行优化join语句,你们都很积极的发言讨论,结论是围绕索引与大小表关系来进行操做,重要的是业务进行绑定。算法
部份内容来源于极客时间的Mysql实战45讲。sql
在Mysql的数据库中,咱们知道join连接主要使用的有大体三种状况。数据库
那这些join咱们须要怎么使用呢?而且可使用的很好,须要咱们在数据库里面尝试下。微信
该数据表来源于网络。网络
-- 建立测试数据库
CREATE DATABASE join_test CHARSET UTF8;
-- 人员信息表
CREATE TABLE `Persons` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`LastName` char(16) NOT NULL DEFAULT '',
`FirstName` char(16) NOT NULL DEFAULT '',
`Address` varchar(128) NOT NULL DEFAULT '',
`City` varchar(128) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 订单表
CREATE TABLE `Orders` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`OrderNo` int(11) NOT NULL DEFAULT '0',
`Pid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Persons` (`LastName`, `FirstName`, `Address`, `City`)
VALUES
('Adams', 'John', 'Oxford Street', 'London'),
('Bush', 'George', 'Fifth Avenue', 'New York'),
('Carter', 'Thomas', 'Changan Street', 'Beijing');
INSERT INTO `Orders` (`OrderNo`, `Pid`)
VALUES (77895, 3), (44678, 3), (22456, 1), (24562, 1), (34764, 65);
复制代码
建立了两个字段的关联关系,而且关联关系这里没有使用索引字段。oop
使用的算法有几种,一个是Index Nested-Loop join,另外就是Block Nested-Loop Join.性能
关联表Peoples,与Order表测试
explain select p.* from Persons p
INNER JOIN Orders o on p.id = o.Pid
复制代码
执行结果图: 优化
从图上能够看出驱动表是Peoples,被驱动表是Order,因为咱们的关联关系中,被驱动表没有索引,因此在执行关联的时候第二张表要全盘扫描。ui
那执行流程是怎样的呢?
结果执行的数量是笛卡尔积,进行乘法。
若是join buffer 里面的数据放不下怎么办?
就先取出来一部分驱动表里面的数据,进行与第二个表对比,循环执行,对比结束后清空buffer中的内容,再处理。
从上面能够看出,当被驱动表上没有使用索引的时候会涉及全盘扫描,而且是两个表都全盘扫描,虽然第一个表内容读取到内存中能够加快数据的读取,可是全盘扫描对于性能属于一个损耗。
因此咱们须要尽量的创建索引
那么若是咱们创建索引了呢?
增长索引 索引的名字 与索引的列
CREATE INDEX Pid ON Orders (Pid)
EXPLAIN select p.* from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid;
复制代码
由于咱们在被驱动的表上增长了索引,因此当咱们须要的是Persons表中的数据时候,能够利用到索引,执行结果以下。
当两个表关联的时候,咱们的People表,还有Order表。选择People选择为驱动表,Order为被动表,使用On关联的时候Order 字段上有索引,那么就会使用该执行算法语句。
算法内容以下:
能够看到是使用的循环驱动表中的数据而后去被驱动表中查找,利用索引,减小第二个循环的次数。这样就能加快速度。
从上面能够看出,在选择使用join的时候,必定要避免sql语句将关联的第二个上使用join语句,咱们能够每次将本身执行的语句加上explain简单的看下sql执行计划,在优化咱们的sql语句。
还有做为驱动表的数据尽量少,循环的数据就不多了。
这就有咱们前面所说的小表做为驱动表,大表加索引。这个概念。
上面咱们说了使用的两个算法,那么咱们在执行过程当中会遇到哪些呢?
重点强调,咱们的语句都每次使用explain来查看输出
inner join 与join语句执行结果是一致的,因此在看执行结果,咱们没必要要关注某个点。
在使用inner join 的时候,以哪一个左表仍是右表做为依赖表都是存在可能的,因此咱们可使用straight_join来强制使用某个表做为依赖表,而且在使用inner join语句的时候该straight_join 也是一个优化的方式。
强制采用某个表做为依赖表。
// 注意当咱们使用join语句,须要查询第二个表数据的时候,若是咱们的where 条件中没有增长 筛选条件可能会致使使用Block Nested-Loop Join
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid;
复制代码
那么这种状况下怎么优化的呢?
从图上能够看出来,咱们的表二没有走索引,致使咱们数据进行全盘的扫描。
在每个数据库的表上,咱们都了解会有主键索引,那么咱们是否能够根据主键索引来排除呢?
咱们经过sql来看。
当OrderNo上没有索引的时候
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid
where o.OrderNo > 30000
复制代码
走的是全盘扫描,若是咱们在OrderNo上加上索引呢?
增长普通索引
CREATE INDEX Pid ON Orders (Pid)
//在我建立索引的时候,有时候条件语句是能够用上索引的,有的时候是用不上的。因为数据量过小的缘由致使部分索引使用补上的状况。在这里根据不一样的字段内容是能使用上索引的。
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid
where o.Pid > 3
复制代码
因此咱们在使用语句的时候须要多多关注索引的使用,关于Tree索引,咱们下次再聊。
从上面能够看到,使用索引能帮助咱们提升不少,可是写入的SQL中能不能执行使用索引,还跟语句的构成有关。
尽可能在写出来的sql都须要执行下explain 检查下执行情况,知道sql的执行结果,这样咱们能真正的写出来好的join语句。
关于使用join,建议使用left join或者right join 提升效率。具体分析下次再聊。
·END·
路虽远,行则必至
本文原发于 同名微信公众号「胖琪的升级之路」,回复「1024」你懂得,给个赞呗。
微信ID:YoungRUIQ