2011-12-10 19 views
0

我無法在此處發佈實際查詢,所以我發佈了查詢的基本大綱,這應該足夠了。該查詢用於尋找並返回一組根據函數的輸出進行排序的用戶,例如F. F從User表和其他已加入的表中獲取參數。該查詢類似如下限制在此查詢中正在處理的行數

Select TOP (20) 
from (select row_number OVER (Order By F desc) as rownum, 
      user.*, .. 
     from user 
     inner join X on user.blah = X.blah 
     left outer join Y on user.foo = Y.foo 
     where DATEDIFF(dd, LastLogin, GetDate()) > 200 and Y.bar > FUBAR) as temp 
where rownum > 0 

根據執行計劃91%的成本是在排序。由於排序是基於F,我無法添加索引來加速排序。內部查詢查詢所有記錄,過濾器然後排序。現在大多數時候用戶只是看1-5頁的結果(1頁有20條記錄,因此Top(20)),所以我想如果有什麼辦法可以限制正在處理和排序的行查詢速度更快,大部分時間CPU佔用更少。

編輯:當我說計算F表加入時,我的意思是這個。 F需要X.blah和Y.foo和Y.bar等參數。而已。所有這些參數也需要作爲結果集的一部分返回。例如用戶的最後位置的緯度和經度存儲在X.

+0

謝謝!我編輯以澄清我的意思。 – shashi

回答

1

不知道和多少它會幫助一個總的想法 - 但兩件事情:

  1. 您是否確定WHERE子句中的所有外鍵列和列(user.blah,X.blah,user.foo,Y.foo,Y.bar)確實已編入索引?這將顯着幫助JOIN性能。

    如果這些列沒有編制索引,那麼SQL Server在執行計劃中可能會有一個排序操作,因此它可以使用數據的合併連接。所以,你的排序甚至可能沒有真正來自您認爲原因排序

  2. 你與行號結合TOP (20)OVER (ORDER BY F DESC),但你不能對整個結果集定義任何真正ORDER BY - 讓你的結果最好是隨機的。另外,如果您已經定義了rownum,不能你只需要使用:

    SELECT (columns) 
    FROM (.......) as temp 
    WHERE rownum BETWEEN 0 AND 20 
    
3

至少你可以嘗試不要叫DATEDIFF在每一行

declare @target_date datetime 
set @target_date = DATEADD(dd, -200, GetDate()) 

Select TOP (20) 
from (select row_number OVER (Order By F desc) as rownum, 
      user.*, .. 
     from user 
     inner join X on user.blah = X.blah 
     left outer join Y on user.foo = Y.foo 
     where LastLogin < @target_date and Y.bar > FUBAR) as temp 
where rownum > 0 

也許做同樣的事情與FUBAR和F?

上面的例子不會給你太多的性能,但提供了有關如何減少函數調用

1

的幾點思考:

  1. 什麼樣的功能是F?它可以重寫爲內聯表值函數嗎?這將使優化器有機會將函數擴展爲可重用的執行計劃。

  2. 你在Y上做了LEFT OUTER JOIN,但是然後在你的WHERE子句中包含Y的一列,實際上將它作爲INNER JOIN來呈現。雖然優化器可能會以相同的方式呈現執行計劃,但我會將其清理乾淨,以便將來更容易排除故障。