背景
最近ssis的開發過程中遇到幾個問題。其中使用cte時,遇到乙個遠端連線物件,結果導致嚴重的效能問題,為了應急我就修改了**。
之前我寫了一篇介紹cte的隨筆包含了cte的用法等:
問題
在乙個資料查詢中遇到乙個遠端連線物件,然後使用了cte,然後本地查詢與遠端物件的cte進行了left join 。下面就是執行計畫:
首先我們發現,最後乙個操作符顯示遠端查詢佔了99%。
注意:
首先,遠端查詢使用的是cte的表示式,我對cte的理解有以下幾點:
1.一次性檢視(adhoc view)。即必須後面跟著相應的select、insert、update等,只能用一次。
2.cte表示式也是在記憶體中建立了乙個表並對其操作。
3.with as 部分僅僅是乙個封裝定義的物件,並沒有真的查詢。
3.除非本身具有索引否則cte中是沒有索引和約束的。
4.沒有專門的統計資訊,這點與表變數很像。有可能會有錯誤的統計資訊。
其次,連線操作符使用的是迴圈巢狀的操作符。這樣就幾何翻倍了查詢的時間。
這裡需要說一下nestedloops:
本質上講,「nested loops」操作符就是:為每乙個記錄的外部輸入找到內部輸入的匹配行。
技術上講,這意味著外表聚集索引被掃瞄獲取外部輸入相關的記錄,然後內錶聚集索引查詢每乙個匹配外表索引的記錄。
以上兩個說法都表明了這種方式導致的效能問題。因為每一次迴圈都要訪問一次鏈結伺服器。當資料很大的時候極大地增加了查詢時間。我這邊70000+的資料執行了半小時。
解決:
既然了解了問題的情況,那我就著手解決問題。主要是兩分解成兩個步驟:
1.將遠端鏈結伺服器的查詢結果插入臨時表。
2.本地資料與臨時表做left join。
對應的執行計畫如下:
可以看到整個效能得到了極大的提高。修改完成後執行時間縮減到20秒以內。效率還是驚人的。
可以對比一下表變數與cte表倒是不同的特點:
通過兩個方式的不同點可知幾種情況不應當使用cte:
1.結果集較大時不應使用。
2.查詢時間較長的不要使用,比如跨伺服器查詢。
3.需要大的表連線的,比如行很多的各種join。尤其沒有索引。
4.多次查詢資料。
5.需要優化相關子查詢。
這些時候使用臨時表甚至表變數將會帶來效能的提公升。具體我就不在這裡細說了有興趣可以一起討論下。
一些網上的錯誤:
1.materialize 提示 可以強制將with as短語裡的資料放入乙個全域性臨時表裡。sql server中根本沒有這個提示。據說2014以後可能會有?
2.cte 效能要差,根據實際情況出發,據我所知在絕大多數情況下,cte的效能要好。尤其是對比游標(迭代)和內建函式的情況下,都會大大提高效能。
3.cte使用了tempdb,沒有僅僅使用了記憶體。
總結:
通過解決實際問題,讓我了解了cte的執行機制。可以理解為一種一次性的檢視。當然我們這裡需要著重說明,cte本身在效能優化上還是有很大作用的,尤其對於遞迴查詢和內建函式的使用時都極大的較少了io。
我猜想cte內部原理應該與游標相似,但是極大的簡化了效能,也許是優化器的功勞。最後由於僅僅使用了記憶體中這樣也大大減少了連線瓶頸。
這部分很多是我的個人觀點,希望各位大神幫忙指摘一下。
sql 遠端連線
步驟 一 看ping 伺服器ip能否ping通。這個實際上是看和遠端sql server 2000伺服器的物理連線是否存在。如果不行,請檢查網路,檢視配置,當然得確保遠端sql server 2000伺服器的ip拼寫正確。其實在伺服器端啟動查詢分析器,輸入 select version 執行後可以看...
sql優化技巧
1.比較運算子能用 就不用 增加了索引的使用機率 2.事先知道只有一條查詢結果時,使用 limit 1 limit 1 可以避免全表掃瞄,找到對應結果就不會再繼續掃瞄了 3.選擇合適的資料型別很重要 能用tinyint就不用smallint,能用smallint就不用int,磁碟和記憶體消耗越小越好...
SQL遠端連線設定
設定 sql server 2008 以允許遠端連線 如果無法通過 ip位址遠端連線你的 sql server 2008 伺服器,可以參考下面的內容進行設定。在進行下述設定之前,應該確保你的網路已經安裝設定完畢,伺服器已經正常連線到網路中。1 單擊windows的 開始 依次選擇 所有程式 micr...