[慢查优化]联表查询注意哪位高手是驱动表 & 你搞不清楚
[慢查优化]联表查询注意谁是驱动表 你搞不清楚谁join谁更好时请放手让mysql自行判定 写在前面的话: ?? 不要求每个人一定理解 联表查询 (join/left join/inner join 等 ) 时的 mysql 运算过程; ??? 不要求每个人一定知道线上 (现在或未来) 哪张表数据量大
[慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定写在前面的话:
?? 不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程;
???不要求每个人一定知道线上(现在或未来)哪张表数据量大,哪张表数据量小;
????但把mysql客户端(如SQLyog,如HeidiSQL)放在桌面上,时不时拿出来 explain 一把,这是一种美德!
在实例讲解之前,我们先回顾一下联表查询的基础知识。
——联表查询的基础知识——
引子:为什么第一个查询using temporary,第二个查询不用临时表呢?
下面两个查询,它们只差了一个order by,效果却迥然不同。
第一个查询:
EXPLAIN extended
SELECT ads.id
FROM ads, city?
WHERE
? ?city.city_id = 8005
? ?AND ads.status = 'online'
? ?AND city.ads_id=ads.id
ORDER BY?ads.id?desc
执行计划为:
??? id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????? rows? filtered? Extra???????????????????????? ?
------? -----------? ------? ------? --------------? -------? -------? --------------------? ------? --------? -------------------------------
???? 1? SIMPLE?????? city??? ref???? ads_id,city_id? city_id? 4??????? const?????????????????? 2838??? 100.00? Using temporary; Using filesort
???? 1? SIMPLE?????? ads???? eq_ref? PRIMARY???????? PRIMARY? 4??????? city.ads_id?????? 1??? 100.00? Using where???????????????????
第二个查询:
执行计划里没有了using temporary: ??? id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????? rows? filtered? Extra???????????????????? ?EXPLAIN extended
SELECT ads.id
FROM ads,city?
WHERE
? ?city.city_id =8005
? ?AND ads.status = 'online'
? ?AND city.ads_id=ads.id
ORDER BY?city.ads_id?desc
------? -----------? ------? ------? --------------? -------? -------? --------------------? ------? --------? ---------------------------
???? 1? SIMPLE?????? city??? ref???? ads_id,city_id? city_id? 4??????? const?????????????????? 2838??? 100.00? Using where; Using filesort
???? 1? SIMPLE?????? ads??? eq_ref? PRIMARY???????? PRIMARY? 4??????? city.ads_id?????? 1??? 100.00? Using where??????????????? 为什么? ? DBA告诉我们: ? ? MySQL 表关联的算法是 Nest Loop Join,是通过驱动表的结果集作为循环基础数据,然后一条一条地通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。 ? EXPLAIN 结果中,第一行出现的表就是驱动表(Important!) ? 以上两个查询语句,驱动表都是 city,如上面的执行计划所示! ? 对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序(Important!) 因此,order by ads.id desc 时,就要先 using temporary 了! ? 驱动表的定义 wwh999?在 2006年总结说,当进行多表连接查询时,?[驱动表]?的定义为:
1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表];
2)未指定联接条件时,行数少的表为[驱动表](Important!)。 ? 忠告:如果你搞不清楚该让谁做驱动表、谁 join 谁,请让 MySQL 运行时自行判断 既然“未指定联接条件时,行数少的表为[驱动表]”了, 而且你也对自己写出的复杂的 Nested Loop Join 不太有把握(如下面的实例所示), 就别指定谁 left/right join 谁了, 请交给 MySQL优化器 运行时决定吧。 如果您对自己特别有信心,可以像火丁一样做优化。 ? 小结果集驱动大结果集 de.cel?在2012年总结说,不管是你,还是 MySQL, 优化的目标是尽可能减少JOIN中Nested Loop的循环次数, 以此保证:
永远用小结果集驱动大结果集(Important!)!
——实例讲解—— ? Nested Loop Join慢查SQL语句 先了解一下 mb 表有 千万级记录,mbei 表要少得多。慢查实例如下:
explain SELECT mb.id, …… FROMmb?LEFT JOIN mbei ON mb.id=mbei.mb_id?INNER JOINu ON mb.uid=u.uid ? WHERE 1=1 ? ORDER BY mbei.apply_time DESC limit 0,10够复杂吧。Nested Loop Join 就是这样, 以驱动表的结果集作为循环的基础数据,然后将结果集中的数据作为过滤条件一条条地到下一个表中查询数据,最后合并结果;此时还有第三个表,则将前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此反复。 这条语句的执行计划如下: ??? id? select_type? table?? type??? possible_keys?? key???????????? key_len? ref???????????????????? rows? Extra????????????????????????????????????? ?
------? -----------? ------? ------? --------------? --------------? -------? -------------------? -------? --------------------------------------------
???? 1? SIMPLE?????? mb????? index?? userid????????? userid????????? 4??????? (NULL)?????????????? 6060455? Using index; Using temporary; Using filesort
???? 1? SIMPLE?????? mbei??? eq_ref? mb_id? mb_id? 4??????? mb.id???????????? 1???????????????????????????????????????????? ?
???? 1? SIMPLE?????? u?????? eq_ref? PRIMARY???????? PRIMARY???????? 4??????? mb.uid??????? 1? Using index???????????????????????????????? 由于动用了“LEFT JOIN”,所以攻城狮已经指定了驱动表,虽然这张驱动表的结果集记录数达到百万级! . . 如何优化? . . 优化第一步:LEFT JOIN改为JOIN 干嘛要 left join 啊?直接 join!
explain SELECT mb.id……立竿见影,驱动表立刻变为小表 mbei 了, Using temporary 消失了,影响行数少多了: ??? id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????????????? rows? Extra??????? ?
FROM mb?JOIN mbei ON mb.id=mbei.mb_id?INNER JOINu ON mb.uid=u.uid ? WHERE 1=1 ? ORDER BY mbei.apply_time DESC limit 0,10
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 1? SIMPLE?????? mbei??? ALL???? mb_id? (NULL)?? (NULL)?? (NULL)???????????????????????? 13383? Using filesort
???? 1? SIMPLE?????? mb????? eq_ref? PRIMARY,userid? PRIMARY? 4??????? mbei.mb_id?????? 1?????????????? ?
???? 1? SIMPLE?????? u?????? eq_ref? PRIMARY???????? PRIMARY? 4??????? mb.uid??????????????? 1? Using index??
优化第一步之分支1:根据驱动表的字段排序,好吗? left join不变。干嘛要根据非驱动表的字段排序呢?我们前面说过“对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序!”的。
explain SELECT mb.id……也满足业务场景,做到了rows最小: ??? id? select_type? table?? type??? possible_keys?? key???????????? key_len? ref??????????????????? rows? Extra???? ?
FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id?INNER JOINu ON mb.uid=u.uid ? WHERE 1=1 ? ORDER BY?mb.id DESC limit 0,10
------? -----------? ------? ------? --------------? --------------? -------? -------------------? ------? -----------
???? 1? SIMPLE?????? mb????? index?? userid????????? PRIMARY???????? 4??????? (NULL)?????????????????? 10??????????? ?
???? 1? SIMPLE?????? mbei??? eq_ref? mb_id? mb_id? 4??????? mb.id??????????? 1? Using index
???? 1? SIMPLE?????? u?????? eq_ref? PRIMARY???????? PRIMARY???????? 4??????? mb.uid?????? 1? Using index ?
优化第二步:去除所有JOIN,让MySQL自行决定! 写这么多密密麻麻的 left join/inner join 很开心吗?
explain SELECT mb.id……立竿见影,驱动表一样是小表 mbei: ??? id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????????????? rows? Extra??????? ?
FROM mb,mbei,u? ?
WHERE
?? ?mb.id=mbei.mb_id
?? ?and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 1? SIMPLE?????? mbei??? ALL???? mb_id? (NULL)?? (NULL)?? (NULL)???????????????????????? 13388? Using filesort
???? 1? SIMPLE?????? mb????? eq_ref? PRIMARY,userid? PRIMARY? 4??????? mbei.mb_id?????? 1?????????????? ?
???? 1? SIMPLE?????? u?????? eq_ref? PRIMARY???????? PRIMARY? 4??????? mb.uid??????????????? 1? Using index??
最后的总结: 强调再强调:
不要过于相信你的运气! 不要相信你的开发环境里SQL的执行速度! 请拿起 explain 武器, 如果你看到以下现象,请优化:? ?? 记住,explain 是一种美德!
- 出现了Using temporary;
- rows过多,或者几乎是全表的记录数;
- key 是 (NULL);
- possible_keys 出现过多(待选)索引。
参考资源: 1)wwh999,2006,进行多表查时的排序问题,其多表查询时的原理论证!?; 2)de.cel,2012,MySQL中的Join 原理及优化思路?; 3)火丁,2013,MySQL优化的奇技淫巧之STRAIGHT_JOIN; ? 赠图一枚:


핫 AI 도구

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

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

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

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

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

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Logitech ghub 드라이버는 win7을 지원하지 않습니까? 호환되지 않습니다. Windows 7은 업데이트를 중단하고 더 이상 Microsoft의 기본 운영 체제가 아니기 때문에 Logitech ghub와 같은 많은 새로운 소프트웨어가 더 이상 이를 지원하지 않습니다. Logitech 드라이버의 기본 인터페이스: 1. 기본 소프트웨어 인터페이스는 왼쪽에 있습니다. 세 개의 버튼은 조명, 버튼 및 감도 설정입니다. 2. 조명 인터페이스 설정에서 일반적인 특수 효과는 비교적 일반적이며 시청각 효과는 사운드 주파수에 따라 색상을 변경할 수 있으며 고음, 중음 및 저음 대역에 따라 설정할 수 있습니다. , 다양한 색상과 효과가 있습니다. 3. 버튼 설정에서 사용자는 특별한 요구 사항에 따라 여기에서 버튼을 편집할 수 있습니다. 4. 감도 설정에서 많은 사용자는 DPI 속도 전환 지점을 직접 추가할 수 있지만 일부는 자체 설정이 있습니다.

12306 티켓 예매 앱의 최신 버전을 다운로드하세요. 모두가 매우 만족하는 여행 티켓 구매 소프트웨어입니다. 소프트웨어에서 제공되는 다양한 티켓 소스가 있어 매우 편리합니다. - 실명인증으로 온라인 구매가 가능합니다. 모든 사용자가 쉽게 여행티켓과 항공권을 구매하고 다양한 할인 혜택을 누릴 수 있습니다. 또한 사전에 예약하고 티켓을 얻을 수도 있습니다. 호텔을 예약하거나 차량으로 픽업 및 하차할 수도 있습니다. 한 번의 클릭으로 원하는 곳으로 이동하고 티켓을 구매할 수 있어 여행이 더욱 간편해지고 편리해집니다. 모든 사람의 여행 경험이 더욱 편안해졌습니다. 이제 편집자가 온라인으로 자세히 설명합니다. 12306명의 사용자에게 과거 티켓 구매 기록을 볼 수 있는 방법을 제공합니다. 1. 철도 12306을 열고 오른쪽 하단의 My를 클릭한 후 My Order를 클릭합니다. 2. 주문 페이지에서 Paid를 클릭합니다. 3. 유료페이지에서

Xuexin.com에서 내 학업 자격을 어떻게 확인하나요? Xuexin.com에서 학업 자격을 확인할 수 있습니다. 많은 사용자가 Xuexin.com에서 학업 자격을 확인하는 방법을 모릅니다. 다음으로 편집자는 Xuexin.com에서 학업 자격을 확인하는 방법에 대한 그래픽 튜토리얼을 제공합니다. 유저들이 와서 구경해 보세요! Xuexin.com 사용 튜토리얼: Xuexin.com에서 학업 자격을 확인하는 방법 1. Xuexin.com 입구: https://www.chsi.com.cn/ 2. 웹사이트 쿼리: 1단계: Xuexin.com 주소를 클릭합니다. 위의 홈페이지에 들어가려면 [교육 쿼리]를 클릭합니다. 2단계: 최신 웹페이지에서 아래 그림의 화살표와 같이 [쿼리]를 클릭합니다. 3단계: 새 페이지에서 [학점 파일에 로그인]을 클릭합니다. 4단계: 로그인 페이지에서 정보를 입력하고 [로그인]을 클릭합니다.

일부 사용자는 win11 컴퓨터용 드라이버를 설치할 때 몇 가지 문제에 직면했습니다. 컴퓨터에 이 파일의 디지털 서명을 확인할 수 없다는 메시지가 표시되어 드라이버를 설치할 수 없게 되었습니다. 자세한 내용은 다음 소개를 참조하십시오. 1. [Win + [Ctrl+Shift+Enter]를 누릅니다. 관리자 권한으로 Windows Powershell 창을 엽니다. 3. 사용자 계정 컨트롤 창에서 이 응용 프로그램이 장치를 변경할 수 있도록 허용하시겠습니까? 관리자: Windows Powers

MySQL과 PL/SQL은 각각 관계형 데이터베이스와 절차적 언어의 특성을 나타내는 서로 다른 두 가지 데이터베이스 관리 시스템입니다. 이 기사에서는 구체적인 코드 예제를 통해 MySQL과 PL/SQL 간의 유사점과 차이점을 비교합니다. MySQL은 SQL(구조적 쿼리 언어)을 사용하여 데이터베이스를 관리하고 운영하는 인기 있는 관계형 데이터베이스 관리 시스템입니다. PL/SQL은 Oracle 데이터베이스 고유의 절차적 언어로 저장 프로시저, 트리거, 함수 등의 데이터베이스 개체를 작성하는 데 사용됩니다. 같은

시간 복잡도는 입력 크기를 기준으로 알고리즘의 실행 시간을 측정합니다. C++ 프로그램의 시간 복잡성을 줄이는 팁에는 데이터 저장 및 관리를 최적화하기 위한 적절한 컨테이너(예: 벡터, 목록) 선택이 포함됩니다. Quick Sort와 같은 효율적인 알고리즘을 활용하여 계산 시간을 단축합니다. 여러 작업을 제거하여 이중 계산을 줄입니다. 불필요한 계산을 피하려면 조건부 분기를 사용하세요. 이진 검색과 같은 더 빠른 알고리즘을 사용하여 선형 검색을 최적화합니다.

20일 본 사이트 소식에 따르면 AMD는 어제(19일) '온리: 여신의 길'을 지원하는 최신 AMD소프트웨어: 아드레날린 에디션 24.7.1 드라이버 업데이트를 출시했다. 16%) 및 "Zone Zero" 게임. AMD의 드라이버 업데이트에는 "DOTA2" 게임용 Radeon Anti-Lag2 기술도 도입되었습니다. AMD는 이 드라이버를 AMD RDNA 아키텍처를 갖춘 개별 그래픽 카드 및 코어 디스플레이에 설치하면 입력 지연이 더욱 줄어들고 게임 경험이 향상될 수 있다고 공식적으로 밝혔습니다. AMD는 또한 새 드라이버에서 다수의 BUG를 수정했습니다. 정보는 다음과 같습니다. AMD Radeon™ Anti-Lag 및 AMDFi 활성화가 개선되었습니다.

1. 바탕화면에서 키조합(Win키 + R)을 눌러 실행창을 연 후, [regedit]를 입력하고 Enter를 눌러 확인하세요. 2. 레지스트리 편집기를 연 후 [HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorer]를 클릭하여 확장한 다음 디렉터리에 Serialize 항목이 있는지 확인합니다. 없으면 탐색기를 마우스 오른쪽 버튼으로 클릭하고 새 항목을 생성한 다음 이름을 Serialize로 지정합니다. 3. 그런 다음 직렬화를 클릭한 다음 오른쪽 창의 빈 공간을 마우스 오른쪽 버튼으로 클릭하고 새 DWORD(32) 비트 값을 만들고 이름을 Star로 지정합니다.
