2009-01-14 166 views
11

我使用的是SQL查詢類似於以下形式:LEFT OUTER JOIN

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
AND table1.period = table2.period 

而且這兩種方式太慢或有什麼地方鎖死,因爲它至少需要4分鐘返回。如果我要改變它:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table1.period = table2.period 

然後它工作正常(雖然沒有返回正確數量的列)。有什麼辦法可以加快速度嗎?

UPDATE:它做同樣的事情,如果我切換後查詢的最後兩行:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.period = table2.period 
WHERE table1.person_uid = table2.person_uid 

更新2:這些都是實際觀看的是我的加盟。不幸的是,他們在一個我無法控制的數據庫上,所以我無法(輕易地)對索引進行任何更改。我傾向於同意這是一個索引問題。在接受答案之前,我會稍等片刻,以便有一些不可思議的方式來調整我不知道的查詢。否則,我會接受當前的答案之一,並試圖找出另一種方法來做我想做的事情。感謝所有人的幫助。

+0

請爲此查詢提供執行計劃 – squadette 2009-01-14 21:48:51

回答

16

請記住,語句2和3與第一個語句不同。

怎麼樣?那麼,你正在做一個左外連接,你的WHERE子句沒有考慮到這一點(就像ON子句一樣)。至少,請嘗試:

SELECT col1, col2 
FROM table1, table2 
WHERE table1.person_uid = table2.person_uid (+) 
AND table1.period = table2.period (+) 

並查看您是否得到相同的性能問題。

你對這些表有什麼指標?這種關係是否由外鍵約束定義?

您可能需要的是person_uid和period(兩個表)上的組合索引。

+0

查詢錯誤,我不能混合ANSI外部聯接和舊式外部聯接。 – 2009-01-14 21:58:43

3

您是否對這兩個表的person_uidperiod都有索引?

如果不是,請添加它們並重試。

查看執行計劃並查看查詢實際正在執行的操作。

另請參見:字段的數據類型是什麼?兩張桌子都一樣嗎?隱含的演員可以真的放慢速度。

+0

嗯,問題標記爲oracle,所以我不認爲他使用的是SQL Server。 – cletus 2009-01-14 21:57:44

+0

啊:)我沒有看到......無所謂......執行計劃也可在oracle中使用......我將編輯答案。 – 2009-01-14 21:59:26

2

這些表是否在您加入的列上有索引?安裝Oracle的免費SQLDeveloper產品,並使用它對該查詢執行「解釋」,並查看它是否正在對兩個表進行順序掃描。

5

我認爲你需要理解爲什麼最後兩個不是第一個查詢。如果您執行了一個左連接,然後添加了一個where子句來引用連接右側的表中的一個字段(可能並不總是有一條記錄與第一個表匹配的字段),那麼您已經有效地將連接更改爲內連接。有一個例外,那就是如果你引用像

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table2.person_uid is null 

在這種情況下,你要求不具有在第二表中的記錄備案。但是除了這種特殊情況之外,如果您在where子句中指定table2中的字段,則會將左連接更改爲內連接。

如果您的查詢速度不夠快,我想看看你的索引。

2

在左連接中你會掃描表1爲(person_uid,週期),每個獨特組合,那麼對於所有相應的記錄有搜索表2。如果table2沒有合適的索引,則可能涉及掃描整個表格。

我最好的猜測,沒有看到一個執行計劃,是第一個查詢(這似乎是正確的唯一一個)是有表掃描表2和表1。

正如你說,你不能改變的指標,您需要更改查詢。據我所知,只有一個現實的選擇...

SELECT 
    col1, col2 
FROM 
    table2 
FULL OUTER JOIN 
    table1 
     ON table1.person_uid = table2.person_uid 
     AND table1.period = table2.period 
WHERE 
    table1.person_uid IS NOT NULL 

這裏的希望是,你掃描(person_uid,週期)的每個唯一組合表2,但要在表1索引的使用。 (而不是掃描table1,並使用table2上的索引,這是我期望從您的查詢中得到的結果)

但是,如果table1沒有合適的索引,那麼您將不太可能看到任何性能改進所有...

Dems。

0

在更新之一的OP說他實際上是查詢視圖中不表。在這種情況下,可以通過直接查詢他需要的表來增加性能,特別是在視圖非常複雜的情況下,可以加入許多其他不包含所需信息的表或者他們是調用視圖的視圖。

0

ANSI連接語法提供了JOIN條件和FILTER謂詞之間非常明確的區別;編寫外部連接時這非常重要。使用EMP /部門表,請看從以下兩個外的結果連接

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
and loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
RESEARCH    20      DALLAS 
SALES     30      CHICAGO 
OPERATIONS    40      BOSTON 

====

Q2 
SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
where loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
OPERATIONS    40      BOSTON 

第一個例子,示出了Q1是的一個例子「加入恆定」。實質上,在執行外連接之前應用過濾條件。因此,您可以消除行,隨後將其作爲外連接的一部分添加回來。這不一定是錯誤的,但是您真正要求的查詢是?通常情況下,Q2中顯示的結果是必需的,在(外部)連接之後應用過濾器。

對於大型數據集也有性能影響。在許多情況下,加入常量必須由優化器通過創建橫向視圖進行內部解析,通常只能通過嵌套循環連接進行優化,而不是散列連接

對於熟悉Oracle外部連接語法,查詢可能會被寫爲

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
     ,emp e 
where d.deptno = e.deptno(+) 
and loc in ('NEW YORK','BOSTON') 

該查詢在語義上等同於上面的Q2。

因此,總而言之,在編寫ANSI外連接時理解JOIN子句和WHERE子句之間的差異非常重要。