Join的實現算法有三種,分別是Nested Loops Join, Merge Join, Hash Join。
DB2、SQL Server和Oracle都是使用這三種方式,不過Oracle選擇使用nested loop的條件跟SQL Server有點差別,內存管理機制跟SQL Server不一樣,因此查看執行計划,Oracle中nested loops運用非常多,而merge和hash方式相對較少,SQL Server中,merge跟hash方式則是非常普遍
優化原則
1.若有單行謂詞,則他的表一定是驅動表(select * from employees e,departments d where e.department_id=d.department_id and e.department_id=100 and salary=10000; 上面的語句中e.department_id=d.department_id是連接謂詞,e.department_id=100是非連接謂詞(對連接列的限制),salary=10000是單行謂詞(對非連接列的限制))
2.外連接時,一定是用顯示的行數比較多的那個表作為驅動表。如:
select e.employee_id,e.department_id,d.manager_id,d.location_id from employees e right join departments d on e.department_id=d.department_id
則departments表顯示的行數一定大於等於employees表,所以應該要以departments表作為驅動表,如果以employees表作為驅動表,則departments表中多顯示的那幾行就顯示不出來了
4.一般情況下,Hash Join處理代價非常高,是數據庫服務器內存和CPU的頭號殺手之一,尤其是涉及到分區(數據量太大導致內存不夠的情況,或者並發訪問很高導致當前處理線程無法獲得足夠的內存,那么數據量不是特大的情況下也可能需要進行分區),為了盡快的完成所有的分區步驟,將使用大量異步的I/O操作,因此期間單一一個線程就可能導致多個磁盤驅動器出於忙碌狀態,這很有可能阻塞其它線程的執行。
5. 要避免大數據的Hash Join,盡量將其轉化為高效的Merge Join、Nested Loops。可能使用的手段有表結構設計、索引調整設計、SQL優化,以及業務設計優化。例如冗余字段的運用,將統計分析結果用service定期跑到靜態表中,適當的冗余表,使用AOP或類似機制同步更新等。
6. 盡量減少join兩個輸入端的數據量。這一點比較常犯的毛病是,條件不符合SARG((Searchable Arguments),在子查詢內部條件給的不充分(SQL過於復雜情況下SQL Server查詢優化器經常犯傻,寫在子查詢外部的條件不會被用在子查詢內部,影響子查詢內部的效率或者是跟子查詢再join時候的效率)。
參考 :