SQL SERVER 時間換空間,空間換時間 以及什麼是好SQL

希望這期不要掉粉,因爲在說SQL SERVER 但實際上這期如果你放到所有的數據庫上去看,也是有營養的,雖然放到了一般不會發文的週六,也沒想有多少觀衆,就當自己對某些東西的回顧和反思。

先說問題,最近的SQL SERVER 內存消耗的厲害,在這之前是建立了一堆的索引,來提高查詢的效率,內存的使用也在悄然的上漲.

一般來說,數據庫有需求是正常合理的需求,就應該給,大部分人的第一反應,是不是有慢語句,是不是有消耗內存的東西在運行,是否應該優化或殺死。

語句當然要優化,索引當然要加,但過度的優化和大量的索引走向的就是另一個極端。SQL SERVER 本身與其他的 ORACLE ,POSTGRESQL ,MYSQL 三個傳統數據庫在內存的管理方面是比較「放羊」方式的管理,你安裝後最大內存和最小內存都是不用設置的,系統會自動的進行處理。

其實這裏有兩個矛盾點,這在其他的數據庫上也是存在的

1 防止buffer變得過大,以至於系統的內存不足

2 通過最大化緩衝池來最小化數據庫文件頻繁在I/O和內存中頻繁的交換

這是放到大部分數據庫都應該能被認可的一個點, 在一個負載過重的系統上,大型的查詢無法獲得所需要的內存的最小量,帶來的就是處理這個SQL 的等待,而如果此時你的數據庫還支持並行,POSTGRESQL ORACLE SQL SERVER ,等都支持並行,此時的並行對於大型的查詢並不會好到哪裏去,而會讓事情變得更糟糕,因爲我本身內存不足,而你要並行處理,內存就更加的不足,加速I/O的壓力。

所以搞清楚到底是內存不足或軟件的設計上有問題,這兩件事情就被提到了檯面上。個人傾向在目前硬件的價格較低的情況下,儘量的去添加硬件,而軟件的某些架構和處理方式要改變是很難的,這和很多事情都有關,這裏就不展開了。

在SQL SERVER 中如果得不到足夠的內存,則查詢可能會走另外的執行計劃,並且會佔用TEMP庫(物理I/O)的方式處理,而性能就會走向另一個極端。

現在回到上面的那個問題,一個SQL 如果他執行的快,就說明很好,這樣的想法對不對,個人認爲,to young to simple。

我會從以下維度來考慮一個SQL 到底OK 不OK 

1 執行時間,這當然的考慮, 否則你的客戶就要投訴你了

2 每個SQL 佔用的內存(我會對一些複雜的SQL 來看看到底會佔用多少內存,怎麼看後面說)

3  SQL 的複雜度,如果一個SQL 本身很複雜,那就要拆

關於第三個問題可能馬上就有人問,我就喜歡寫複雜的SQL 我又沒有用MYSQL ,ORACLE  SQL SERVER 不就是讓人寫複雜SQL 的,通過一個SQL 來解決複雜的邏輯,不是一件好事情。

實際上這的兩面看,的確一個SQL 能解決的問題,換成多個SQL 來解決,效率上可能還真的是一個SQL 可能佔有優勢,(實際上也不盡其然,很多情況拆開運行倒是比寫一個上百行的SQL 要快),但一般這樣想的人,都沒有一個併發的感念和想法,你的一個SQL 運行下去,會不會在單位時間裏面多次重複運行,那他們要佔有的資源很可能就重疊了,那重疊會怎麼樣,鎖唄,死鎖唄,鎖等待唄,各種latch 鎖唄。  所以SQL 的複雜度和併發本身就是一個矛盾體,放到其他數據庫也是一樣。

另外一個SQL 執行的快慢,他不是固定的,和你的天時地利人和(其實就是資源,併發,單位時間)是綁定的,而機器的資源可是動態的,所以一直強調語句要多少秒執行出來的做法,你的前提是,資源可別短人家的,並且系統的併發到底高不高,執行的頻率是多少,等等問題,而一味要求一個SQL 要多少秒出來,前邊的事情不想,後面的要求就很難達到。

下面是一個數據庫的佔用內存的情況,可以看到有的表的主鍵佔用的內存都已經達到G級別,在證明這個系統很繁忙的情況下,也是能分析出一些其他的問題。

另外一個事情,SQL SERVER 本身是不會亂分配內存的,如果它達到了某個更高的內存消耗標準,自然會申請獲得更多的內存,所以想限制內存的使用只能是徒勞的行爲,最後用磁盤模擬內存那結果也是相當的好看,你可以查看一個數據庫中某個線程的SQL佔用內存的情況,下面這個語句佔用的內存就被捕捉到了,所以在看一個語句的佔用CPU 時間,邏輯掃描數,物理掃描數,還是要關心一下內存的使用情況。

其實在考慮一個SQL 是不是更快的時候,時間的節省,可能帶來的就是空間的損失(這裏不光指的是內存),所以還是那句話,空間換時間,時間換空間,在每種數據庫上都是可以找尋的一句「金句」。在硬件性能不足的情況下,在怎麼優化語句也是徒勞,同時在強悍的硬件,也架不住某些SQL。