2011-08-08 249 views
2

我一直對依賴子查詢的某些查詢存在奇怪的問題。他們運行得很快,直到我在子查詢中使用UNION語句。然後他們無休止地跑,我在10分鐘後給了。我現在描述的場景不是我開始使用的那個場景,但我認爲它解決了很多可能的問題,但卻產生了同樣的問題。所以即使這是一個毫無意義的查詢,請忍受我!使用UNION子查詢進行查詢需要很長時間

我有一個表:

tblUser - 100,000 rows 
tblFavourites - 200,000 rows 

如果我執行:

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser); 

...那麼它運行在第二下。不過,如果我修改它,這樣子查詢有UNION,它將至少運行10分鐘(之前我放棄了!)

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser UNION SELECT uid FROM tblUser); 

一個毫無意義的變化,但它應該產生相同的結果,我不明白爲什麼它需要更長的時間?

將子查詢放入視圖中並調用它,具有相同的效果。

任何想法,爲什麼會這樣?我正在使用SQL Azure。


問題解決了。請參閱下面的答案。


+0

因爲查詢會消除重複的結果,所以'UNION'將花費相當長的一段時間。它本質上是對結果集做一個DISTINCT。執行「UNION ALL」會得到更快的結果,但是如果存在重複項,它們將不會從結果集中消除。 –

+0

感謝您的快速響應。我將它改成了UNION ALL,並且在5分鐘後仍然運行。但是,我將數據庫下載到本地SQL Server 2008,問題消失了。 UNION的查詢幾乎和沒有查詢一樣快。然後,我在單獨的SQL Azure數據庫上運行查詢,並遇到同樣的問題。所以它看起來像一個SQL Azure問題。我會聯繫Azure支持。謝謝! –

+0

每當聯盟給我的問題,通常是因爲它阻止自己。嘗試做兩個插入到表變量,然後在你的地方使用。 – cadrell0

回答

1

原來,問題是指數的,由於一個... tblFavourites包含兩個外鍵在tblUser主鍵(UID):

userId 
otherUserId 

兩列具有相同的定義和相同的指標,但我發現在原始查詢中交換userId for otherUserId解決了問題。

我跑:

ALTER INDEX ALL ON tblFavourites REBUILD 

...和問題走了。查詢現在幾乎立即執行。

我不太瞭解Sql Server/Azure幕後發生的事情......但我只能想象它是一個受損的索引或其他什麼東西?我經常更新統計數據,但沒有任何效果。

謝謝!

---- UPDATE

以上不完全正確。它確實解決了大約20分鐘的問題,然後它返回。我已經和微軟的支持人員聯繫了好幾天,看起來問題是關於tempDB。他們正在研究解決方案。

+0

如何從tblFavourites.userID到tblUser.uid並擁有'userID NOT IN(SELECT uid FROM tblUser)'返回true,除非userID爲空?在這種情況下,測試'WHERE userID IS NULL'是更快的查詢方式。 –

2

UNION生成唯一值,所以DBMS引擎進行排序。 在這種情況下,您可以安全使用UNION ALL。

3

UNION對組合數據集中的所有字段確實在執行DISTINCT。它在最終結果中過濾掉了愚蠢的東西。

Uid索引?如果沒有,可能需要很長的時間,因爲查詢引擎:

  • 生成的第一個結果集
  • 生成的第二個結果集
  • 篩選出所有的受騙者(其中一半的記錄)在哈希表

如果重複是不是一個問題(以及使用IN意味着它們將不會被),然後使用UNION ALL其去除昂貴排序/過濾步驟。

+0

感謝您的快速響應。我將它改成了UNION ALL,並且在5分鐘後仍然運行。但是,我將數據庫下載到本地SQL Server 2008,問題消失了。 UNION的查詢幾乎和沒有查詢一樣快。然後,我在單獨的SQL Azure數據庫上運行查詢,並遇到同樣的問題。所以它看起來像一個SQL Azure問題。我會聯繫Azure支持。謝謝! –

2

UNION通常通過臨時內存表來實現。你基本上是將你的tblUser複製到內存中,WITH NO INDEX。然後,tblFavourites中的每一行都會產生超過200,000行的完整表掃描 - 即200Kx200K = 400億雙行掃描(因爲查詢引擎必須從兩個錶行中獲取uid)

如果您的tblUser在uid這肯定是真的,因爲SQL Azure中的所有表都必須具有聚簇索引),那麼tblFavourites中的每一行都會進行非常快速的索引查找,從而導致只有200Kxlog(100K)= 200Kx17 = 200K行掃描,每個行都有17個b-tree索引比較(比從數據頁上的一行讀取uid要快得多),所以它應該等於大約200Kx(3-4)或100萬行雙行掃描。我相信較新版本的SQL服務器也可能會構建一個臨時哈希表,只包含uid,所以本質上它會下降到200K行掃描(假設哈希表查找是微不足道的)。

您還應該生成查詢計劃來檢查。

本質上,如果tblUser具有索引(應該在SQL Azure上),則非UNION查詢的運行速度將快500,000倍。

0

我剛碰到這個問題。我有大約100萬行要經過,然後我意識到我的一些身份證在另一張桌子上,所以我聯合起來在一個「不存在」中獲得相同的信息。一分鐘左右後,我從查詢花費約7秒開始處理僅5000行。這似乎有所幫助。我絕對討厭這個解決方案,但我已經嘗試了許多事情,最終都會遇到同樣極其緩慢的執行計劃。這一次在18秒內得到了我需要的東西。

DECLARE @PIDS TABLE ([PID] [INT] PRIMARY KEY) 
    INSERT INTO @PIDS SELECT DISTINCT [ID] FROM [STAGE_TABLE] WITH(NOLOCK) 
    INSERT INTO @PIDS SELECT DISTINCT [OTHERID] FROM [PRODUCTION_TABLE] WITH(NOLOCK) 
     WHERE NOT EXISTS(SELECT [PID] FROM @PIDS WHERE [PID] = [OTHERID] 

    SELECT (columns needed) 
    FROM [ORDER_HEADER] [OH] WITH(NOLOCK) 
    INNER JOIN @PIDS ON [OH].[SOME_ID] = [PID] 

(是的,我試過「其中... EXISTS」的最終選擇...內部聯接是更快) 請讓我再說一遍,我本人來說覺得這實在是太醜了,但其實我在我的過程中兩次使用這個連接,所以從長遠來看這將節省我的時間。希望這可以幫助。

0

難道不是更有意義從

「用戶ID是不是在該表和/或表衝擊片雷管的所有ID的組合列表上的」

改寫的問題

「用戶ID不在此表上,而不是在該表無論是

SELECT COUNT(*) 
FROM tblFavourites 
WHERE userID NOT IN (SELECT uid FROM tblUser) 
AND userID NOT IN (SELECT uid FROM tblUser);