sql優化 表連接join方式


 
 
sql優化核心 是數據庫中 解析器+優化器的工作,我覺得主要有以下幾個大方面:
1>掃表的方法(索引非索引、主鍵非主鍵、書簽查、索引下推)
2>關聯表的方法(三種),關鍵是內存如何利用
3>處理排序聚合的方法,如何利用內存

即 少掃磁盤多用內存

--=====2 表關聯方式
-----0 概述
類別 Nested Loop Hash Join Merge Join
使用條件 任何條件 等值連接(=) 等值或非等值連接(>,<,=,>=,<=),‘<>’除外
相關資源 CPU、磁盤I/O 內存、臨時空間 內存、臨時空間

Nested Loop 優點: 當有高選擇性索引或進行限制性搜索時效率比較高,能夠快速返回第一次的搜索結果。
缺點: 當索引丟失或查詢條件限制不夠時,效率低;當表紀錄數多時,效率低
實現: 從一張表中讀取數據,訪問另一張表(通常是索引)來做匹配,nested loops適用的場合是當一個關聯表比較小的時候,效率會更高

Hash Join 優點: 當無索引或索引條件模糊時,Hash Join比Nested Loop有效。通常比Merge Join快。在數據倉庫環境下,如果表的紀錄數多,效率高
缺點: 為建立哈希表,需要大量內存。第一次的結果返回較慢
實現: 將一個表(通常是小一點的那個表)做hash運算,將列數據存儲到hash列表中,從另一個表中抽取記錄,做hash運算,到hash 列表中找到相應的值,做匹配。

Merge Join 優點: 當無索引或索引條件模糊時,Merge Join比Nested Loop有效。非等值連接時,Merge Join比Hash Join更有效
缺點: 所有的表都需要排序。它為最優化的吞吐量而設計,並且在結果沒有全部找到前不返回數據
實現: 先將關聯表的關聯列各自做排序,然后從各自的排序表中抽取數據,到另一個排序表中做匹配,因為merge join需要做更多的排序,所以消耗的資源更多
通常來講,能夠使用merge join的地方,hash join都可以發揮更好的性能



選擇什么連接類型有以下三要素:
1) 表大小
2) 連接列是否有索引
3) 連接列是否要排序
不同DBMS對表連接的支持:
1) SqlServer, Oracle支持以下三種連接
2) Mysql5.5前支持NestedLoop,之后支持對其的優化算法Block Nested-Loop

-----1 Nested Loop Join
驅動表(outer table),另一個為inner table,驅動表中的每一行與inner表中的相應記錄JOIN。類似一個嵌套的循環。適用於驅動表的記錄集比較小(<10000)且inner表的連接列上要有Index。
注意:驅動表的記錄集一定要小,inner表的連接列要有(UniqueIndex更好)索引。處理過程偽代碼:
for oi in count(outer table 行數):do
for ii in count(inner table 行數):do --若inner連接列有主鍵索引,則不用循環inner表,也不需要回表,效率超高
if oi.column=ii.column:do --若只是普通索引,還需要回表查相應數據(可能需要大量的隨機IO),可能會慢許多,但也比沒索引強
Send To Client
fi
done
done


--Block Nested-Loop Join(僅Mysql支持)
因為普通Nested-Loop一次只將一行傳入內層循環, 所以outer table (的結果集)有多少行, 內存循環便要執行多少次.
在inner table的連接上有索引的情況下,其掃描成本為O(Rn),若沒有索引,則掃描成本為O(Rn*Sn)。如果inner table有很多記錄,則Nested-Loops Join會掃描內部表很多次,執行效率會非常差。

BNL算法:將outer table結果集存入join buffer, 內層循環的每一行與整個Join buffer中的記錄做比較,從而減少內層循環的次數。
舉例,outer table結果集是100行,使用NLJ 需掃描內部表100次,如使用BNL,先把Outer Loop表每次讀取的10行記錄放到join buffer,然后在InnerLoop表中直接匹配這10行數據,
內存循環就可以一次與這10行進行比較, 這樣只需要比較10次,對內部表的掃描減少了9/10。所以BNL算法就能夠顯著減少內層循環表掃描的次數.

MySQL使用Join Buffer有以下要點:
當MySQL的 Join 有使用到 Block Nested-Loop Join,那么調大變量join_buffer_size 才是有意義的。而前面的 Index Nested-Loop Join如果僅使用索引進行Join,那么調大這個變量則毫無意義
a) 只有在join類型為all, index, range的時候才可以使用join buffer。
b) 能夠被buffer的每一個join都會分配一個buffer, 也就是說一個query最終可能會使用多個join buffer。
c) 第一個nonconst table不會分配join buffer, 即便其掃描類型是all或者index。
d) 在join之前就會分配join buffer, 在query執行完畢即釋放。
e) join buffer中只會保存參與join的列, 並非整個數據行。
f) 5.6版本及以后,優化器管理參數optimizer_switch中的block_nested_loop控制着BNL是否被用於優化器。默認條件下是開啟,若果設置為off,優化器在選擇 join方式的時候會選擇NLJ算法。

-----2 Hash Join
將兩表中較小的在內存中構造一個HASH表(只對連接列),掃描另一個表,同樣對JOIN KEY進行HASH后探測是否可以JOIN。適用於記錄集比較大的情況。
需要注意的是:如果HASH表太大,無法一次構造在內存中,則分成若干個partition,寫入磁盤的temporary segment,則會多一個寫的代價,會降低效率



-----3 Sort Merge Join
通常情況下Hash Join的效果都比排序合並連接要好,然而如果行源已經被排過序,在執行排序合並連接時不需要再排序了,這時排序合並連接的性能會優於散列連接。
可以使用USE_MERGE(table_name1 table_name2)來強制使用排序合並連接.
Sort Merge join 用在沒有索引,並且數據已經排序的情況.

將兩個表排序,然后將兩個表合並。通常情況下,只有在以下情況發生時,才會使用此種JOIN方式:
1.RBO模式 且 HASH_JOIN_ENABLED=false
2.不等價關聯(>,<,>=,<=,<>)
3.數據源已排序


免責聲明!

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



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