mysql優化---in型子查詢,exists子查詢,from 型子查詢


in型子查詢引出的陷阱:(掃更少的行,不要臨時表,不要文件排序就快)

題: 在ecshop商城表中,查詢6號欄目的商品, (注,6號是一個大欄目)
最直觀的: mysql> select goods_id,cat_id,goods_name from  goods where cat_id in (select cat_id from category where parent_id=6);

誤區: 給我們的感覺是, 先查到內層的6號欄目的子欄目,如7,8,9,11
然后外層, cat_id in (7,8,9,11)

事實: 如下圖, goods表全掃描, 並逐行與category表對照,看parent_id=6是否成立

原因: mysql的查詢優化器,針對In型做優化,被改成了exists的執行效果.
當goods表越大時, 查詢速度越慢.

改進: 用連接查詢來代替子查詢
 explain select goods_id,g.cat_id,g.goods_name from  goods as g
 inner join (select cat_id from category where parent_id=6) as t
 using(cat_id) \G

內層 select cat_id from ecs_category where parent_id=6 ; 用到Parent_id索引, 返回4行
+--------+
| cat_id |
+--------+
|      7 |
|      8 |
|      9 |
|     11 |
+--------+    形成結果,設為t    



*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: ecs_category
         type: ref
possible_keys: parent_id
          key: parent_id
      key_len: 2
          ref:
         rows: 4
        Extra:
3 rows in set (0.00 sec)


第2次查詢, 
t和 goods 通過 cat_id 相連, 
因為cat_id在 goods表中有索引, 所以相當於用7,8,911,快速匹配上 goods的行.
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: g
         type: ref
possible_keys: cat_id
          key: cat_id
      key_len: 2
          ref: t.cat_id
         rows: 6
        Extra:

第1次查詢 :
是把上面2次的中間結果,直接取回.
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4
        Extra:
exists子查詢:
題: 查詢有商品的欄目.
按上面的理解,我們用join來操作,如下:
mysql> select c.cat_id,cat_name from ecs_category as c inner join  goods as g
 on c.cat_id=g.cat_id group by cat_name; (見36)

優化1:  在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型 比 char型 分組,也要快一些.(見37)


優化2: 在group時, 我們假設只取了A表的內容,group by 的列,盡量用A表的列,
會比B表的列要快.(見38)

優化3: 從語義上去優化
select cat_id,cat_name from ecs_category where exists(select *from  goods where  goods.cat_id=ecs_category.cat_id) (見40)

|       36 | 0.00039075 | select c.cat_id,cat_name from ecs_category as c inner
join  goods as g on c.cat_id=g.cat_id group by cat_name
              |
|       37 | 0.00038675 | select c.cat_id,cat_name from ecs_category as c inner
join  goods as g on c.cat_id=g.cat_id group by cat_id
              |
|       38 | 0.00035650 | select c.cat_id,cat_name from ecs_category as c inner
join  goods as g on c.cat_id=g.cat_id group by c.cat_id
              |
|       40 | 0.00033500 | select cat_id,cat_name from ecs_category where exists
(select * from  goods where  goods.cat_id=ecs_category.cat_id)
              |

from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.因為是一個臨時形成的結果。
所以: from的返回內容要盡量少.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM