2026/3/26 18:28:39
网站建设
项目流程
湖北省建设部网站公告,如何设置的iis后台服务网站地址,seo工资服务,app推广概念
NLJ#xff0c;全称 Index Nested-Loop Join#xff08;基于索引的嵌套循环关联#xff09;。它是MySQL 在执行 JOIN 时最常用、也是效率最高的算法之一。
它的核心思想是#xff1a;用驱动表的每一行#xff0c;去被驱动表的索引里做等值查找#xff0c;从而把“…概念NLJ全称Index Nested-Loop Join基于索引的嵌套循环关联。它是MySQL 在执行 JOIN 时最常用、也是效率最高的算法之一。它的核心思想是用驱动表的每一行去被驱动表的索引里做等值查找从而把“内层全表扫描”变成“索引点查”复杂度从 O(N×M) 降到 O(N×logM)。首先说出结论NLJ是非常棒的方案效能非常高99%的情况建议大家使用NLJ。示例表 student1 和 student2 结构如下CREATE TABLE student1 ( id bigint NOT NULL AUTO_INCREMENT, name varchar(200), no varchar(100), PRIMARY KEY (id), ) ENGINEInnoDB CREATE TABLE student2 ( id bigint NOT NULL AUTO_INCREMENT, name varchar(255), no varchar(255), PRIMARY KEY (id), KEY idx_no (no) ) ENGINEInnoDB说明表student1有100条数据表student2有999条数据表 student2 的 no 字段建了索引。执行如下SQLexplain select s1.id, s1.name, s1.no, s2.name from student1 s1 join student2 s2 on s2.no s1.no分析explain结果得出A、驱动表是s1被驱动表是s2查看方法见 通过Explain分析驱动表。B、对表s1进行了全表扫描通过typeALL得出关联表 s2 用上了表s2的字段no上的索引通过 keyidx_no 得出。这个语句的执行流程是这样的1、从表 s1 中读入一行数据 M;2、从数据行M中取出no字段到表s2的索引no上去查找;3、取出表s2中满足条件的行跟M组成一行作为结果集的一部分;4、重复执行步骤1到3直到表s1的末尾循环结束。这个过程是先遍历表s1然后根据从表s1中取出的每行数据中的no值去表s2的索引no上查找满足条件的记录。在形式上这个过程就跟我们写程序时的嵌套查询类似并且可以用上被驱动表的索引所以我们称之为“IndexNested-Loop Join”简称 NLJ。它对应的流程图如下所示注A、这个过程对驱动表 s1 做了全表扫描这个过程需要扫描 100 行而对于每一行 M根据 no 字段去表 s2 查找走的是树搜索过程。假如数据都是一一对应的每次的搜索过程都只扫描一行也是总共扫描 100 行所以整个执行流程总扫描行数是 200。B、在这种算法中外层循环驱动表的每一行都会用来查找内层循环被驱动表中的匹配行这个过程可以通过索引来完成一步步地找个后面关联表的匹配行形成一部分数据就写到 net_buffer里net_buffer满了就推给客户端因此整个过程是一个边查询数据边推送的过程不需要把某一个表的数据暂存因此不需要使用join_buffer边查边推是所有数据库都用的方案这就是为什么查询了一个巨大的表没有占满内存。C、NLJ算法时间复杂度O(N × logM)N 为驱动表行数M 为被驱动表行数。其中 N 对整个算法影响最大故应该降低 N 的值也就是用小表做驱动表。D、使用NLJ 的前提是被驱动表inner table的关联字段上有索引主键、唯一索引或普通二级索引皆可所以我们要给被驱动表建立合适的索引。E、NLJ算法是一种非常优秀的方案99%的情况使用NLJ是非常合适的但也有极个别的情况MySQL优化器估算会认为NLJ 成本低于 Block Nested-LoopBNL或 Hash Join从而不使用NLJ这种情况这里不再详细说明。F、不光MySQL其他数据库如 PostGreSQL、Oracle等也是这种思想。是否应该用Join很多人说最好的方法是不用join但是为什么不用用和不用有什么区别对底层细节说不清楚下面咱一起分析一下。对于示例中的SQL假设不使用 join那我们就只能用单表查询。我们看看上面这条语句的需求我们只能在程序java/php/python....里这样做1、执行 select s1.id, s1.name, s1.no from s1 查出表 s1 的数据这里有 100 行2、循环遍历这 100 行数据从每一行 M 取出字段 no 的值 $M.no执行select s2.name from s2 where no$M.no把返回的结果和 M 构成结果集的一行。可以看到在这个查询过程也是扫描了 200 行但执行了 101 次查询就有101个I/O比直接 join 多了100 次。除此之外程序里还要自己拼接 SQL 语句和结果显然还不如直接 join 好。于是我们得出结论对于这种join比较少的情况完全可以放心使用 Join。尽量不要做太多表关联查询一旦数据量上来很难优化。总结再次说出结论99%的情况下我们要通过给被驱动表建索引使 Join 查询使用NLJ以提升查询效率。