이 기사에서는 MySQL의 조인문 알고리즘에 대한 심층적인 이해를 제공하고, 조인문의 최적화 방법에 대해 이야기하는 것이 도움이 되기를 바랍니다.
1. Join 문 알고리즘
두 개의 테이블 t1과 t2를 생성합니다.
CREATE TABLE `t2` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `a` (`a`) ) ENGINE=InnoDB; CREATE DEFINER=`root`@`%` PROCEDURE `idata`() BEGIN declare i int; set i=1; while(i<p>두 테이블 모두 기본 키 인덱스 id와 인덱스 a를 가지며 b 필드에는 인덱스가 없습니다. 저장 프로시저 idata()는 테이블 t2에 1000행의 데이터를 삽입하고, 테이블 t1</p><h3 id="strong-에-행의-데이터를-삽입했습니다-Index-Nested-Loop-Join-strong"><strong>1에 100행의 데이터를 삽입했습니다. Index Nested-Loop Join</strong></h3><pre class="brush:php;toolbar:false">select * from t1 straight_join t2 on (t1.a=t2.a);
조인 문을 직접 사용하면 MySQL 최적화 프로그램이 테이블 t1 또는 t2를 구동 테이블로 선택하고 Straight_join을 사용하여 MySQL이 고정 연결을 사용하여 쿼리를 실행하도록 합니다. 이 문에서 t1은 구동 테이블이고 t2는 구동 테이블 t2에 필드 a에 대한 인덱스가 있습니다. 조인 프로세스는 이 인덱스를 사용하므로 이 문의 실행 흐름은 다음과 같습니다. 1. 테이블 t1에서 데이터 R의 행을 읽습니다.
의 끝에서 끝날 때까지 1~3단계를 반복합니다.
이 프로세스를 구동할 수 있습니다. 테이블의 인덱스를 Index Nested-Loop Join 또는 줄여서 NLJ라고 합니다.이 프로세스에서는:
입니다.
조인이 사용되지 않는다고 가정하면 단일 테이블로만 쿼리할 수 있습니다. 1. 테이블 t1의 모든 데이터를 찾으려면select * from t1
을 실행하세요. 2. 다음 100개 데이터 행을 반복합니다. select * from t1
,查出表t1的所有数据,这里有100行
2.循环遍历这100行数据:
- 从每一行R取出字段a的值$R.a
- 执行
select * from t2 where a=$R.a
각 행에서 $R.a 필드의 값을 가져옵니다. R - 실행
select * from t2 where a=$R.a
반환된 결과를 넣습니다. 그리고 R을 사용하여 결과 집합의 행을 형성합니다
이 쿼리 프로세스도 200개의 행을 스캔했지만 총 101개의 문을 실행했습니다. 이는 직접 조인보다 100번 더 많은 상호 작용입니다. 또한 클라이언트는 SQL 문과 결과를 자체적으로 연결해야 합니다. 이것은 직접 조인하는 것만큼 좋지 않습니다
- 주도 테이블의 인덱스를 사용할 수 있는 경우:
- 조인 문을 사용하면 강제로 여러 개의 단일 테이블로 분할하여 SQL을 실행하는 것보다 성능이 좋습니다. 문
조인 문을 사용하는 경우 작은 테이블을 구동 테이블로 사용해야 합니다
2. Simple Nested-Loop Join
select * from t1 straight_join t2 on (t1.a=t2.b);테이블 t2의 필드 b에는 인덱스가 없으므로 전체 테이블 스캔을 위해 t2로 갈 때마다 이를 수행해야 합니다. 이 알고리즘을 단순 중첩 루프 조인이라고 합니다이런 방식으로 계산하면 이 SQL 요청은 테이블 t2를 최대 100회 스캔하여 총 100*100=100,000개 행을 스캔합니다.
MySQL은 이 단순 중첩 루프 조인을 사용하지 않습니다. 하지만 BNL
3이라고 하는 Block Nested-Loop Join이라는 또 다른 알고리즘을 사용합니다. Block Nested-Loop Join
제어 테이블에 사용 가능한 인덱스가 없습니다. 1. 테이블 넣기 t1의 데이터를 스레드 메모리 Join_buffer로 읽습니다. 이 명령문은 select *로 작성되었으므로 테이블 t1 전체가 메모리에 넣습니다2. table t2, Join_buffer 안의 데이터를 비교하여 조인 조건에 맞는 데이터를 결과 세트로 반환합니다. 이 과정에서 테이블 t1과 테이블 t2 모두에 대해 전체 테이블 스캔이 수행되므로 스캔된 전체 행은 번호는 1100입니다. Join_buffer는 순서가 없는 배열로 구성되어 있으므로 테이블 t2의 각 행에 대해 100번의 판단이 이루어져야 합니다. 메모리에서 이루어져야 하는 총 판단 횟수는 100*1000=100,000번입니다
Simple Nested-Loop Join 알고리즘을 사용하세요. 쿼리를 수행하며, 스캔된 행 수도 100,000행입니다. 따라서 시간 복잡도 측면에서 이 두 알고리즘은 동일합니다. 그러나 Block Nested-Loop Join 알고리즘의 이러한 100,000번의 판단은 메모리 작업이므로 훨씬 더 빠르고 성능이 더 좋습니다. 작은 테이블의 행 수가 N이고 큰 테이블의 행 수가 M이라고 가정합니다. 이 알고리즘에서는:
1) 두 테이블 모두 Full Table Scan을 수행하므로, 스캔된 총 행 수는 M + N입니다.
1)扫描表t1,顺序读取数据行放入join_buffer中,假设放到第88行join_buffer满了
2)扫描表t2,把t2中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回
3)清空join_buffer
4)继续扫描表t1,顺序读取最后的12行放入join_buffer中,继续执行第2步
由于表t1被分成了两次放入join_buffer中,导致表t2会被扫描两次。虽然分成两次放入join_buffer,但是判断等值条件的此时还是不变的
假设,驱动表的数据行数是N,需要分成K段才能完成算法流程,被驱动表的数据行数是M 。这里的K不是常数,N越大K 就会越大,因此把K表示为λ ∗ N ,λ的取值范围是(0,1)。所以,在这个算法的执行过程中:
1.扫描行数是N + λ ∗ N ∗ M
2.内存判断N ∗ M
考虑到扫描行数,N 小一些,整个算式的结果会更小。所以应该让小表当驱动表
4、能不能使用join语句?
1.如果可以使用Index Nested-Loop Join算法,也就是说可以用上被驱动表上的索引,其实是没问题的
2.如果使用Block Nested-Loop Join算法,扫描行数就会过多。尤其是在大表上的join操作,这样可能要扫描被驱动表很多次,会占用大量的系统资源。所以这种join尽量不要用
5、如果使用join,应该选择大表做驱动表还是选择小表做驱动表
1.如果是Index Nested-Loop Join算法,应该选择小表做驱动表
2.如果是Block Nested-Loop Join算法:
- 在join_buffer_size足够大的时候,是一样的
- 在join_buffer_size不够大的时候,应该选择小表做驱动表
在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成以后,计算参数join的各个字段的总数据量,数据量小的那个表,就是小表,应该作为驱动表
二、join语句优化
创建两个表t1、t2
create table t1(id int primary key, a int, b int, index(a)); create table t2 like t1; CREATE DEFINER = CURRENT_USER PROCEDURE `idata`() BEGIN declare i int; set i=1; while(i<=1000)do insert into t1 values(i, 1001-i, i); set i=i+1; end while; set i=1; while(i<=1000000)do insert into t2 values(i, i, i); set i=i+1; end while; END;
在表t1中,插入了1000行数据,每一行的a=1001-id的值。也就是说,表t1中字段a是逆序的。同时,在表t2中插入了100万行数据
1、Multi-Range Read优化
Multi-Range Read(MRR)优化主要的目的是尽量使用顺序读盘
select * from t1 where a>=1 and a<p>主键索引是一棵B+树,在这棵树上,每次只能根据一个主键id查到一行数据。因此,回表是一行行搜索主键索引的</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/5c16d719738fb23caf97d38d00c1644b-5.png?x-oss-process=image/resize,p_40" class="lazy" alt="MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)"></p><p>如果随着a的值递增顺序查找的话,id的值就变成随机的,那么就会出现随机访问,性能相对较差</p><p><strong>因为大多数的数据都是按照主键递增顺序插入得到的,所以如果按照主键的递增顺序查询,对磁盘的读比较接近顺序读,能够提升读性能</strong></p><p>这就是MRR优化的设计思路,语句的执行流程如下:</p><p>1.根据索引a,定位到满足条件的记录,将id值放入read_rnd_buffer中</p><p>2.将read_rnd_buffer中的id进行递增排序</p><p>3.排序后的id数组,依次到主键id索引中查记录,并作为结果返回</p><p>read_rnd_buffer的大小是由read_rnd_buffer_size参数控制的。如果步骤1中,read_rnd_buffer放满了,就会先执行完步骤2和3,然后清空read_rnd_buffer。之后继续找索引a的下个记录,并继续循环</p><p>如果想要稳定地使用MRR优化的话,需要设置<code>set optimizer_switch="mrr_cost_based=off"</code></p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/5c16d719738fb23caf97d38d00c1644b-6.png?x-oss-process=image/resize,p_40" class="lazy" alt="MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)"></p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/3833cfce76c7a34447aff9e3973bd58a-7.png?x-oss-process=image/resize,p_40" class="lazy" alt="MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)"><br> explain结果中,Extra字段多了Using MRR,表示的是用上了MRR优化。由于在read_rnd_buffer中按照id做了排序,所以最后得到的结果也是按照主键id递增顺序的</p><p><strong>MRR能够提升性能的核心在于,这条查询语句在索引a上做的是一个范围查询,可以得到足够多的主键id。这样通过排序以后,再去主键索引查数据,才能体现出顺序性的优势</strong></p><h3 id="strong-Batched-Key-Access-strong"><strong>2、Batched Key Access</strong></h3><p>MySQL5.6引入了Batched Key Access(BKA)算法。这个BKA算法是对NLJ算法的优化</p><p>NLJ算法流程图:</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/3833cfce76c7a34447aff9e3973bd58a-8.png?x-oss-process=image/resize,p_40" class="lazy" alt="MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)"></p><p>NLJ算法执行的逻辑是从驱动表t1,一行行地取出a的值,再到被驱动表t2去做join</p><p>BKA算法流程图:</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/3833cfce76c7a34447aff9e3973bd58a-9.png?x-oss-process=image/resize,p_40" class="lazy" alt="MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)"></p><p>BKA算法执行的逻辑是把表t1的数据取出来一部分,先放到一个join_buffer,一起传给表t2。在join_buffer中只会放入查询需要的字段,如果join_buffer放不下所有数据,就会将数据分成多段执行上图的流程</p><p>如果想要使用BKA优化算法的话,执行SQL语句之前,先设置</p><pre class="brush:php;toolbar:false">set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
其中前两个参数的作用是启用MRR,原因是BKA算法的优化要依赖与MRR
3、BNL算法的性能问题
InnoDB对Buffer Pool的LRU算法做了优化,即:第一次从磁盘读入内存的数据页,会先放在old区域。如果1秒之后这个数据页不再被访问了,就不会被移动到LRU链表头部,这样对Buffer Pool的命中率影响就不大
如果一个使用BNL算法的join语句,多次扫描一个冷表,而且这个语句执行时间超过1秒,就会在再次扫描冷表的时候,把冷表的数据页移到LRU链表头部。这种情况对应的,是冷表的数据量小于整个Buffer Pool的3/8,能够完全放入old区域的情况
如果这个冷表很大,就会出现另外一种情况:业务正常访问的数据页,没有机会进入young区域。
由于优化机制的存在,一个正常访问的数据页,要进入young区域,需要隔1秒后再次被访问到。但是,由于join语句在循环读磁盘和淘汰内存页,进入old区域的数据页,很可能在1秒之内就被淘汰了。这样就会导致MySQL实例的Buffer Pool在这段时间内,young区域的数据页没有被合理地淘汰
BNL算法对系统的影响主要包括三个方面:
1.可能会多次扫描被驱动表,占用磁盘IO资源
2.判断join条件需要执行M∗N次对比,如果是大表就会占用非常多的CPU资源
3.可能会导致Buffer Pool的热数据被淘汰,影响内存命中率
4、BNL转BKA
一些情况下,我们可以直接在被驱动表上建索引,这时就可以直接转成BKA算法了
如果碰到一些不适合在被驱动表上建索引的情况,可以考虑使用临时表。大致思路如下:
select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<p>1)把表t2中满足条件的数据放在临时表tmp_t中</p><p>2)为了让join使用BKA算法,给临时表tmp_t的字段b加上索引</p><p>3)让表t1和tmp_t做join操作</p><p>SQL语句写法如下:</p><pre class="brush:php;toolbar:false">create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;insert into temp_t select * from t2 where b>=1 and b<h3 id="strong-扩展hash-join-strong"><strong>5、扩展hash join</strong></h3><p>MySQL的优化器和执行器不支持哈希join,可以自己实现在业务端,实现流程大致如下:</p><p>1.<code>select * from t1;</code>取得表t1的全部1000行数据,在业务端存入一个hash结构</p><p>2.<code>select * from t2 where b>=1 and b获取表t2中满足条件的2000行数据</code></p><p>3.把这2000行数据,一行一行地取到业务端,到hash结构的数据表中寻找匹配的数据。满足匹配的条件的这行数据,就作为结果集的一行</p><p>【相关推荐:<a href="https://www.php.cn/course/list/51.html" target="_blank" textvalue="mysql视频教程">mysql视频教程</a>】</p>
위 내용은 MySQL의 조인문 알고리즘에 대한 심층적인 이해(최적화 방법 소개)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템으로, 주로 데이터를 신속하고 안정적으로 저장하고 검색하는 데 사용됩니다. 작업 원칙에는 클라이언트 요청, 쿼리 해상도, 쿼리 실행 및 반환 결과가 포함됩니다. 사용의 예로는 테이블 작성, 데이터 삽입 및 쿼리 및 조인 작업과 같은 고급 기능이 포함됩니다. 일반적인 오류에는 SQL 구문, 데이터 유형 및 권한이 포함되며 최적화 제안에는 인덱스 사용, 최적화 된 쿼리 및 테이블 분할이 포함됩니다.

MySQL은 데이터 저장, 관리, 쿼리 및 보안에 적합한 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1. 다양한 운영 체제를 지원하며 웹 응용 프로그램 및 기타 필드에서 널리 사용됩니다. 2. 클라이언트-서버 아키텍처 및 다양한 스토리지 엔진을 통해 MySQL은 데이터를 효율적으로 처리합니다. 3. 기본 사용에는 데이터베이스 및 테이블 작성, 데이터 삽입, 쿼리 및 업데이트가 포함됩니다. 4. 고급 사용에는 복잡한 쿼리 및 저장 프로 시저가 포함됩니다. 5. 설명 진술을 통해 일반적인 오류를 디버깅 할 수 있습니다. 6. 성능 최적화에는 인덱스의 합리적인 사용 및 최적화 된 쿼리 문이 포함됩니다.

MySQL은 성능, 신뢰성, 사용 편의성 및 커뮤니티 지원을 위해 선택됩니다. 1.MYSQL은 효율적인 데이터 저장 및 검색 기능을 제공하여 여러 데이터 유형 및 고급 쿼리 작업을 지원합니다. 2. 고객-서버 아키텍처 및 다중 스토리지 엔진을 채택하여 트랜잭션 및 쿼리 최적화를 지원합니다. 3. 사용하기 쉽고 다양한 운영 체제 및 프로그래밍 언어를 지원합니다. 4. 강력한 지역 사회 지원을 받고 풍부한 자원과 솔루션을 제공합니다.

InnoDB의 잠금 장치에는 공유 잠금 장치, 독점 잠금, 의도 잠금 장치, 레코드 잠금, 갭 잠금 및 다음 키 잠금 장치가 포함됩니다. 1. 공유 잠금을 사용하면 다른 트랜잭션을 읽지 않고 트랜잭션이 데이터를 읽을 수 있습니다. 2. 독점 잠금은 다른 트랜잭션이 데이터를 읽고 수정하는 것을 방지합니다. 3. 의도 잠금은 잠금 효율을 최적화합니다. 4. 레코드 잠금 잠금 인덱스 레코드. 5. 갭 잠금 잠금 장치 색인 기록 간격. 6. 다음 키 잠금은 데이터 일관성을 보장하기 위해 레코드 잠금과 갭 잠금의 조합입니다.

MySQL 쿼리 성능이 좋지 않은 주된 이유는 인덱스 사용, 쿼리 최적화에 의한 잘못된 실행 계획 선택, 불합리한 테이블 디자인, 과도한 데이터 볼륨 및 잠금 경쟁이 포함됩니다. 1. 색인이 느리게 쿼리를 일으키지 않으며 인덱스를 추가하면 성능이 크게 향상 될 수 있습니다. 2. 설명 명령을 사용하여 쿼리 계획을 분석하고 Optimizer 오류를 찾으십시오. 3. 테이블 구조를 재구성하고 결합 조건을 최적화하면 테이블 설계 문제가 향상 될 수 있습니다. 4. 데이터 볼륨이 크면 분할 및 테이블 디비전 전략이 채택됩니다. 5. 높은 동시성 환경에서 거래 및 잠금 전략을 최적화하면 잠금 경쟁이 줄어들 수 있습니다.

데이터베이스 최적화에서 쿼리 요구 사항에 따라 인덱싱 전략을 선택해야합니다. 1. 쿼리에 여러 열이 포함되고 조건 순서가 수정되면 복합 인덱스를 사용하십시오. 2. 쿼리에 여러 열이 포함되어 있지만 조건 순서가 고정되지 않은 경우 여러 단일 열 인덱스를 사용하십시오. 복합 인덱스는 다중 열 쿼리를 최적화하는 데 적합한 반면 단일 열 인덱스는 단일 열 쿼리에 적합합니다.

MySQL 느린 쿼리를 최적화하려면 SlowQueryLog 및 Performance_Schema를 사용해야합니다. 1. SlowQueryLog 및 Set Stresholds를 사용하여 느린 쿼리를 기록합니다. 2. Performance_schema를 사용하여 쿼리 실행 세부 정보를 분석하고 성능 병목 현상을 찾고 최적화하십시오.

MySQL 및 SQL은 개발자에게 필수적인 기술입니다. 1.MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템이며 SQL은 데이터베이스를 관리하고 작동하는 데 사용되는 표준 언어입니다. 2.MYSQL은 효율적인 데이터 저장 및 검색 기능을 통해 여러 스토리지 엔진을 지원하며 SQL은 간단한 문을 통해 복잡한 데이터 작업을 완료합니다. 3. 사용의 예에는 기본 쿼리 및 조건 별 필터링 및 정렬과 같은 고급 쿼리가 포함됩니다. 4. 일반적인 오류에는 구문 오류 및 성능 문제가 포함되며 SQL 문을 확인하고 설명 명령을 사용하여 최적화 할 수 있습니다. 5. 성능 최적화 기술에는 인덱스 사용, 전체 테이블 스캔 피하기, 조인 작업 최적화 및 코드 가독성 향상이 포함됩니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

Dreamweaver Mac版
시각적 웹 개발 도구

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전
