Sql-Server

比較左連接和外部應用做同樣的事情

  • May 5, 2016

我在一個表上有一個更新觸發器,該觸發器在另一個數據庫/表中插入行

查詢看起來像

insert into otherdb.table
select manyfield
from inserted
 left join (select id, 
                   timestamp, 
                   row_number() over (partition by id order by timestamp desc) as rownum
            from sometable) as t1
     on inserted.id = t1.id and
        rownum = 1

sometable有超過 700 萬行並且有適當的索引

在執行執行計劃時,我可以看到如果有 1 個更新的行,則視窗功能(使用正確的名稱?)檢索整個表對行編號並執行一次,它使用索引掃描

相同(它將檢索 700 萬行)如果插入有 20 行或插入有 50,000 行

現在該觸發器的使用主要是 1 行更新(我們確實有一些奇怪的情況,它將是 20-100 行甚至數千行)

我重構了這個查詢看起來像

insert into otherdb.table
select manyfield
from inserted
 outer apply join (select top 1 id, 
                   timestamp
                   from sometable
                   where inserted.id = sometable.id
                   order by timestamp desc) as t1

最後的結果相同,但執行計劃發生了變化。

現在它正在使用索引搜尋,它會為每個插入的行返回 1 行

當我對 50,000 行進行大量更新時,執行計劃將告訴我執行左連接版本時的執行次數為 50,000而不是一個。

恢復一切;

左連接:所有插入的行都重用了 1 個大操作

外部應用:每個插入的行執行一次小操作

我的問題是,此時我對執行計劃的了解還不夠,無法決定我應該保留哪種連接,左連接還是外部應用

這同時被 500-1000 個使用者使用,我們有超時錯誤可能與這個觸發器有關,我們目前使用左連接查詢

編輯

一些實際執行計劃的結果,選擇 55017 行

左連接:

估計子樹成本: ~78 記憶體授予: ~ 156k估計行數: ~57k

外用:

估計子樹成本: ~99 記憶體授予: ~163k 估計行數: ~55k

混合(狗仔隊的解決方案,但使用內連接,左連接見上文):

估計子樹成本: ~87 記憶體授予: ~170k 估計行數: ~56k


一些實際執行計劃的結果,更新 55017 行(觸發器)

左連接:

估計子樹成本: ~401 記憶體授權: ~455k 估計行數: ~225k

外用:

估計子樹成本: ~136 記憶體授予: ~153k 估計行數: ~52k

混合(狗仔隊的解決方案,但使用內連接,左連接見上文):

估計子樹成本: ~126 記憶體授予: ~ 156k估計行數: ~53k

試試這個 - 你可能會得到最好的

select manyfield 
from  ( select manyfield
            , row_number() over (partition by t1.id order by t1.timestamp desc) as rownum 
         from inserted 
         left join sometable t1 
                on inserted.id = t1.id
     ) tt
where rownum = 1 or t1.id is null 

引用自:https://dba.stackexchange.com/questions/137546