[慢查優化]聯表查詢注意誰是驅動表 你搞不清楚誰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???????????????????

第二個查詢:

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

執行計劃里沒有了using temporary:
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 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……
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
立竿見影,驅動表立刻變為小表 mbei 了, Using temporary 消失了,影響行數少多了:
id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????????????? rows? Extra??????? ?
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 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……
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
也滿足業務場景,做到了rows最小:
id? select_type? table?? type??? possible_keys?? key???????????? key_len? ref??????????????????? rows? Extra???? ?
------? -----------? ------? ------? --------------? --------------? -------? -------------------? ------? -----------
???? 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……
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
立竿見影,驅動表一樣是小表 mbei:
id? select_type? table?? type??? possible_keys?? key????? key_len? ref???????????????????????????? rows? Extra??????? ?
------? -----------? ------? ------? --------------? -------? -------? ----------------------------? ------? --------------
???? 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 武器,
如果你看到以下現象,請優化:
  • 出現了Using temporary;
  • rows過多,或者幾乎是全表的記錄數;
  • key 是 (NULL);
  • possible_keys 出現過多(待選)索引。
?
記住,explain 是一種美德!

參考資源:
1)wwh999,2006,進行多表查時的排序問題,其多表查詢時的原理論證!?
2)de.cel,2012,MySQL中的Join 原理及優化思路?
3)火丁,2013,MySQL優化的奇技淫巧之STRAIGHT_JOIN;
贈圖一枚:
http://ww3.sinaimg.cn/bmiddle/97f224aagw1e8fffdvbtkg20b404qu0x.gif

轉載于:https://www.cnblogs.com/zhengyun_ustc/p/slowquery1.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377836.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

四、梯度下降歸一化操作

一、歸一化 Ⅰ什么是歸一化? 答:其實就是把數據歸一到0-1之間,也就是縮放。 常用的歸一化操作是最大最小值歸一化,公式如下: 例如:1,3,5,7,9,10…

[轉帖][強烈推薦]網頁表格(Table/GridView)標題欄和列凍結(跨瀏覽器兼容)

GridView的標題欄、列凍結效果(跨瀏覽器版) 本文來源:http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/02/18/supertable-plugin-for-jquery.aspx 稍早發表了GridView 的標題列凍結效果,足以滿足工作上的需求,不過存在兩個缺點:…

psu是什么電腦配件_PSU的完整形式是什么?

psu是什么電腦配件PSU:電源部門/公共部門事業 (PSU: Power Supply Unit / Public Sector Undertaking) 1)PSU:電源設備 (1) PSU: Power Supply Unit) PSU is an abbreviation of the "Power Supply Unit". PSU是“電源設備”的縮寫 。 It is a…

【C++grammar】斷言與表達式常量

目錄1、常量表達式和constexpr關鍵字2、斷言與C11的靜態斷言1.1. assert : C語言的宏(Macro),運行時檢測。1.2. assert()依賴于NDEBUG 宏1.3. assert 幫助調試解決邏輯bug (部分替代“斷點/單步調試”)2.1static_assert (C11的靜態斷言 )2.2.…

一些又用的國內著名期刊

記: 電子學報、電子與信息學報、圖像圖形學報、自動化學報、計算機學報、軟件學報、計算機研究與發展。轉載于:https://www.cnblogs.com/nanyangzp/p/3322244.html

一、Arduino UNO R3將數據上傳至云平臺

一、準備工作 ①ESP12E Shield ②Arduino UNO R3開發板 ③把ESP12E Shield安裝到Arduino UNO R3開發板上 ④登錄物聯網平臺注冊個賬號,到時候需要使用。 ⑤記錄下來你的Uid和key到時候會用到 ⑥創建個設備,用于測試 ⑦beyondyanyu為設備名&…

怎樣做一個快樂的ASP.NET程序員

首先我想解釋一下標題中兩個關鍵字: "快樂", "ASP.NET程序員". 有的人想成為一個"杰出"的程序員, 或者"資深"的程序員, 簡單來說就是"大牛"級的人物 -- 但是本文不是針對此種發展方向不是說我不鼓勵大家朝這方向走, 而是對我…

__eq___C ++'and_eq'關鍵字和示例

__eq__"and_eq" is an inbuilt keyword that has been around since at least C98. It is an alternative to & (Bitwise AND Assignment) operator and it mostly uses for bit manipulations. “ and_eq”是一個內置關鍵字,至少從C 98起就存在。 它…

leetcode 93. 復原IP地址 思考分析

題目 給定一個只包含數字的字符串,復原它并返回所有可能的 IP 地址格式。 有效的 IP 地址 正好由四個整數(每個整數位于 0 到 255之間組成,且不能含有前導 0),整數之間用 ‘.’ 分隔。 例如:“0.1.2.201” …

二、通過云平臺反向控制Arduino UNO R3

該篇博文是在第一篇博文(一、Arduino UNO R3將數據上傳至云平臺)的基礎上進行的 一、云平臺發送指令反向控制Arduino UNO R3 ESP12E Shield開關都推到OFF(要不然下載會報錯),往Arduino UNO R3開發板上下載下面的代碼 這段代碼進行測試要點&…

使用MSBuild編譯FsLex項目

FsLex FsYacc微軟本身也提供了一個項目模板。但是這個項目模板是lex和yacc文件均包含。我想只適用lex,但是如果每次使用命令行也覺得不夠方便,于是還是研究了一番MsBuild的使用。 使用msbuild hellp.fsproj /v:d 可以查看整個msbuild的流程,非…

Python字符串格式:%vs.format

Often the string formatters in python are referred to as old style and new style. The old-style is % and .format is known as the new style. python中的字符串格式化程序通常被稱為舊樣式和新樣式。 舊樣式為% ,. format被稱為新樣式。 Simple…

【C++grammar】代理構造、不可變對象、靜態成員

目錄1、Delegation Constructor(代理構造)1. What is delegating constructor? (什么是代理構造/委托構造)2. Avoiding recursive calls of target constructors (避免遞歸調用目標ctor)3. 委托構造的好處2、不可變對象和類1、如何讓類成為“不可變類”…

paip.最新的c++ qt5.1.1環境搭建跟hello world

paip.最新的c qt5.1.1環境搭建跟hello world 作者Attilax , EMAIL:1466519819qq.com 來源:attilax的專欄 地址:http://blog.csdn.net/attilax 有一段時間沒接觸c了...今天下載新的qt下來研究一番.. qt的環境搭建有eclipseqtdtmingwqtl…

RFID模塊+WIFI模塊+振動傳感器+有源蜂鳴器+舵機+Arduino UNO R3所構成的門禁系統模塊

該系統模塊主要由RFID模塊WIFI模塊振動傳感器有源蜂鳴器舵機Arduino UNO R3組成的門禁系統模塊。這里使用舵機充當門鎖,用戶可以刷卡開門,也可以通過APP控制舵機狀態達到開門的效果。若有不法分子想要強行進入室內,對門進行撞擊或者人為的破壞…

PushManager

http://suchandalex.googlecode.com/svn/trunk/beOui/beWe/client/Classes/PushNotificationManager.m轉載于:https://www.cnblogs.com/vincent-lu/archive/2012/01/18/2325740.html

krsort_PHP krsort()函數與示例

krsortPHP krsort()函數 (PHP krsort() function) krsort() function is used to sort an associative array in descending order based on the keys, as we know that an associative array contains keys and values, this method sorts an array according to the keys. kr…

ESP12E Shield+Arduino UNO R3開發板+DHT11溫濕度模塊+雙色LED燈+有源蜂鳴器+光敏電阻模塊+I2CLCD1602液晶顯示器所構成的室內檢測系統

室內檢測系統由ESP12E ShieldArduino UNO R3開發板DHT11溫濕度模塊雙色LED燈有源蜂鳴器光敏電阻模塊I2CLCD1602液晶顯示器所構成。DHT11溫濕度模塊獲取室內溫濕度數據通過I2CLCD1602液晶顯示器進行顯示,另一方面通過ESP12E Shield將數據上傳至云平臺。光敏電阻進行捕…

輸入輸出函數:

一、printf函數:     printf("Hello World!\n");     printf("My age is %d\n",26);     int age 17;     printf("My age is %d\n",age);  %d 或 %i: 帶符號 十進制整數。   %o:不帶符號 八進制整數。   %x:…

leetcode 202. 快樂數 思考分析(哈希集合與雙指針解)

1、題目 編寫一個算法來判斷一個數 n 是不是快樂數。 「快樂數」定義為:對于一個正整數,每一次將該數替換為它每個位置上的數字的平方和,然后重復這個過程直到這個數變為 1,也可能是 無限循環 但始終變不到 1。如果 可以變為 1&am…