2011-10-25 104 views
1

我有一個T-SQL查詢,我想讓它更快。SQL Server T-SQL查詢優化

我有EntityAddress表,並希望帶回地址,如果郵寄地址存在。

有時對於任何給定的實體有多個地址。有一個主要的郵寄地址tinyint,有時會被設置,有時不會,這裏沒有規則可以有5個默認的郵件地址所有的標誌設置或沒有設置標誌。

這對11k行運行大約20秒我真的需要得到這個時間,任何人都可以幫忙嗎?

SELECT 
    e.*, addr.* 
FROM 
    [Entity] e 
    --Address does not always exist 
    --PrimaryAddress is a Not Null TinyInt, sometimes this flag is enable twice for a given entity. 
LEFT OUTER JOIN 
    [Address] addr ON addr.[EntityID] = e.[EntityID] 
    AND addr.Code = 'MAILING'   
    AND addr.[AddressID] = (
     --This remove duplicates but add's a long delay(15 seconds) to execution time. 
     SELECT Top 1 a.[AddressID] 
     FROM [Address] AS a 
     WHERE a.Code = 'MAILING' 
     AND a.[EntityID] = e.[EntityID]  
     ORDER BY a.[PrimaryAddress] DESC) 

還應當指出的是,我不能任何索引添加到兩個表要麼:(

親切的問候 西蒙·傑克遜

+0

這是第三方數據庫,任何修改都不是「支持」的。 – Simon

+0

@marc_s,在不改變索引的情況下,通常會有很多可行的選擇來進行性能調整。 – HLGEM

回答

1

這是您的查詢的簡化版本,我你可以告訴我,

SELECT 
    e.*, 
    addr.* 
FROM 
    [Entity] e 
    OUTER APPLY (
       SELECT TOP(1) * 
       FROM addr as a 
       WHERE a.Code = 'MAILING' 
       AND a.[EntityID] = e.[EntityID] 
       ORDER BY a.[PrimaryAddress] DESC 
      ) as addr 
+0

謝謝,這已經改進了一些東西,顯然第一次運行時間大約是14秒,第二次是2秒。 – Simon

+0

@Simon:使用DBCC FREEPROCCACHE等在運行之前清除緩存 – sll

+0

DBCC FREEPROCCACHE,哦,親愛的,23分鐘和20秒的外層,我現在是我的原始版本。有很多分層視圖。 – Simon

0

如果你是在SQL Server 20上,你會告訴我,如果這會比你的版本更快, 05或更高版本,你可以嘗試以下方法:

WITH ranked AS (
    SELECT 
    *, 
    rn = ROW_NUMBER() OVER (PARTITION BY EntityID ORDER BY [PrimaryAddress] DESC) 
    FROM [Address] 
    WHERE Code = 'MAILING' 
) 
SELECT 
    e.*, a.* 
FROM [Entity] e 
    LEFT JOIN [Address] a ON a.[EntityID] = e.[EntityID] AND a.rn = 1 

此查詢的結果將有超過你那一個微小的差別:會有的rn一個附加列與1的和/或NULL小號在裏面。然而,我不認爲這是一個問題,因爲首先在生產查詢中不推薦使用蒙版SELECT列表,如果這是非生產腳本,那麼一個額外的列將不會妨礙。

參考文獻:

+0

或者你可以在臨時表中做到這一點,而不是CTE,它可以放置缺失的索引。 – HLGEM

+0

測試過這種類型的查詢,平均得到9秒。感謝分享。 – Simon

1

你可以停止使用select *,你兩次返回實體ID,這是浪費服務器和網絡資源。你真的需要其他領域的每一個?消除你不需要的任何東西。無論如何,選擇*不應該用於生產代碼。

您擁有在痛苦的排排運行相關子查詢,請嘗試使用聯接代替:

SELECT  e.*, addr.* 
FROM  [Entity] e  
LEFT JOIN (SELECT addr.* 
      FROM [Address] a 
      JOIN  
       (SELECT Top 1 a.[AddressID]   
       FROM [Address] AS a   
       WHERE a.Code = 'MAILING'   
       AND a.[EntityID] = e.[EntityID]    
       ORDER BY a.[PrimaryAddress] DESC) dedup 
        ON a.address_id = dedup.address_id) addr 
    ON addr.[EntityID] = e.[EntityID] 

而且又沒有使用select *,我不知道你的領域或者我會指定他們以上。

當然,解決這個問題的真正方法是修復設計糟糕的數據庫。它不應該允許多個主要地址(我們通過觸發器強制執行此操作),那麼您不需要昂貴的刪除重複任務。我認識到在你的情況下這是不可能的,但它可能會讓別人考慮他們的設計缺陷。由於這是第三方產品,因此我會要求他們修復該問題以僅允許一個主要地址。最終,如果有足夠的人抱怨,他們可能會。

+0

感謝您的反饋我測試了您的加入,平均需要6秒鐘:) – Simon

+0

我只添加了*以保持簡單並專注於關鍵字段。即使這樣,這裏使用的表格和字段名稱也不能反映真實的名稱,如果你看到了我正在處理的內容,那麼我擔心的答案是關於約定而不是問題。 感謝您的時間和幫助。 – Simon

+0

我已經標記了這個答案,因爲它提供了最快的性能提升。 我喜歡@ Mikael-Eriksson的答案以及它的語法如此簡單,但它慢了幾秒(在我的查詢中)。 – Simon