天天看點

SQL Server 容易忽略的錯誤

概述

因為每天需要稽核程式員釋出的SQL語句,是以收集了一些程式員的一些常見問題,還有一些平時收集的其它一些問題,這也是很多人容易忽視的問題,在以後收集到的問題會補充在文章末尾,歡迎關注,由于收集的問題很多是針對于生産資料,測試且資料量比較大,這裡就不把資料共享出來了,大家了解意思就行。

步驟

大寫T-SQL 語言的所有關鍵字都使用大寫,規範要求。

使用“;”作為 Transact-SQL 語句終止符。雖然分号不是必需的,但使用它是一種好的習慣,對于合并操作MERGE語句的末尾就必須要加上“;”

(cte表表達式除外)

避免使用ntext、text 和 image 資料類型,用 nvarchar(max)、varchar(max) 和 varbinary(max)替代

後續版本會取消ntext、text 和 image 該三種類型

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

---使用計算列查詢(走的是索引掃描)

SQL Server 容易忽略的錯誤

---不使用計算列(走的是索引查找)

SQL Server 容易忽略的錯誤

對比兩個查詢顯然絕大部分情況下走索引查找的查詢性能要高于走索引掃描,特别是查詢的資料庫不是非常大的情況下,索引查找的消耗時間要遠遠少于索引掃描的時間,如果想詳細了解索引的體系結構可以檢視了我前面寫的幾篇關于聚集、非聚集、堆的索引體系機構的文章。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

      發現很多人在建表的時候不會注意這一點,在接下來的工作中當你需要查詢資料的時候你往往需要在WHERE條件中多加一個判斷條件IS NOT NULL,這樣的一個條件不僅僅增加了額外的開銷,而且對查詢的性能産生很大的影響,有可能就因為多了這個查詢條件導緻你的查詢變的非常的慢;還有一個比較重要的問題就是允許為空的資料可能會導緻你的查詢結果出現不準确的問題,接下來我們就舉個例子讨論一下。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

實際情況customerid=3是沒有訂單的,數量應該是0,但是結果是1,count()裡面的字段是左連接配接右邊的表字段,如果你用的是主表字段結果頁是錯誤的。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

大家發現下面語句有沒有什麼問題,查詢結果是怎樣呢?

SQL Server 容易忽略的錯誤

正确查詢結果下查詢出的結果是沒有customerid為3的值

為什麼結果會這樣呢?

大家仔細看應該會發現子查詢的orders表中沒有Customerid字段,是以SQL取的是Customer表的Customerid值作為相關子查詢的比對字段。

是以我們應該給子查詢加上表别名,如果加上表别名,如果字段錯誤的話會有錯誤标示

 正确的寫法:

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

l  查詢時一定不能使用”*”來代替字段來進行查詢,無論你查詢的字段有多少個,就算字段太多無法走索引也避免了解析”*”帶來的額外消耗。

l  查詢字段值列出想要的字段,避免出現多餘的字段,字段越多查詢開銷越大而且可能會因為多列出了某個字段而引起查詢不走索引。

建立測試資料庫

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

建立索引

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

查詢測試

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

由于建的索引‘IX1_Customer’沒有包含ModifiedDate字段,是以需要通過鍵查找去聚集索引中擷取該字段的值

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

由于查詢語句中沒有對ModifiedDate字段進行查詢,是以隻走索引查找就可以查詢到需要的資料,是以建議在查詢語句中列出你需要的字段而不是為了友善用*來查詢所有的字段,如果真的

需要查詢所有的字段也同樣建議把所有的字段列出來取代‘*’。

減少網絡通信量。調用一個行數不多的存儲過程與直接調用SQL語句的網絡通信量可能不會有很大的差别,可是如果存儲過程包含上百行SQL語句,那麼其性能絕對比一條一條的調用SQL語句要高得多。

執行速度更快。有兩個原因:首先,在存儲過程建立的時候,資料庫已經對其進行了一次解析和優化。其次,存儲過程一旦執行,在記憶體中就會保留一份這個存儲過程緩存計劃,這樣下次再執行同樣的存儲過程時,可以從記憶體中直接調用。

更強的适應性:由于存儲過程對資料庫的通路是通過存儲過程來進行的,是以資料庫開發人員可以在不改動存儲過程接口的情況下對資料庫進行任何改動,而這些改動不會對應用程式造成影響。

布式工作:應用程式和資料庫的編碼工作可以分别獨立進行,而不會互相壓制。

更好的封裝移植性。

安全性,它們可以防止某些類型的 SQL 插入攻擊。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

 了解TRUNCATE和DELETE的差別

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

 TRUNCATE操作沒有記錄删除日志操作

主要的原因是因為TRUNCATE操作不會激活觸發器,因為TRUNCATE操作不會記錄各行的日志删除操作,是以當你需要删除一張表的資料時你需要考慮是否應該如有記錄日志删除操作,而不是根據個人的習慣來操作。

事務的了解

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

1.簡單的事務送出

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

2.TRY...CATCH

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

3.打開XACT_ABORT

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

當 SET XACT_ABORT 為 ON 時,如果執行 Transact-SQL 語句産生運作時錯誤,則整個事務将終止并復原。

當 SET XACT_ABORT 為 OFF 時,有時隻復原産生錯誤的 Transact-SQL 語句,而事務将繼續進行處理。如果錯誤很嚴重,那麼即使 SET XACT_ABORT 為 OFF,也可能復原整個事務。OFF 是預設設定。

編譯錯誤(如文法錯誤)不受 SET XACT_ABORT 的影響。

SQL Server 容易忽略的錯誤

      是以我們應該根據自己的需求選擇正确的事務。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

你平時在寫T_SQL語句的時候WHERE條件後面的字段的先後順序你有注意嗎?

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

如果這是你的寫的查詢語句

我現在根據你的查詢語句建立一條索引

分别執行三條查詢語句

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

執行計劃分别為

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

 從上面三天查詢語句可以看出,隻有第一條語句走的是索引查找,另外兩條語句走的是索引掃描,而我們從字段的名稱應該可以看的出OID字段應該是該表的一個外鍵字段也是經常會被用作查詢的字段。

接下來我們重新換一下索引順序

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

依然執行前面的三條查詢語句分析執行計劃

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

 分析執行計劃前面兩條查詢語句都走的是索引查找,第三條查詢的是索引掃描,而根據一般單獨用第三條查詢的業務應該不會常見,是以現在一條索引解決了兩個常用查詢的索引需求,避免了建兩條索引的必要(是以當你建索引的時候索引的順序很重要,一般把查詢最頻繁的字段設第一個字段,可以避免建多餘的索引)。

為什麼要把這個問題提出來呢,因為平時有遇到程式員在寫查詢語句的時候對于同一個查詢條件每次的寫法都不一樣,往往是根據自己想到哪個字段就寫哪個字段先,這樣的習慣往往是不好的,就好比上面的例子如果别人看到你的查詢條件建一個索引也是這樣寫的話往往一個表會出現很多多餘的索引(或許有人會說DBA建好索引的順序就好了,這裡把這個因素排除吧),像後面的那個索引就解決了兩個查詢的需求。

是以這裡我一般是這樣規定where條件的,對于經常用作查詢的字段放在第一個位置(比如上面例子的OID),其它的字段根據表的實際字段順序排列,這樣往往你的查詢語句走索引的機率會更大。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

看到這結果是不是有點疑惑,我在連接配接條件裡面寫了TA.stats<>'1',為什麼結果還會查詢出。

接下來我們換一種寫法吧!

SQL Server 容易忽略的錯誤

 接下來我就解釋一下原因:對于外連接配接,連接配接條件不會改變主表的資料,即不會删減主表的資料

對于上面的查詢主表是orders,是以無論你在連接配接條件on裡面怎樣設定主表的條件都不影響主表資料的輸出,影響主表資料的輸出隻在where條件裡,where條件影響最後資料的輸出。而對于附表Customer 的條件就應該寫在連接配接條件(on)裡而不是where條件裡,這裡說的是外連接配接(包括左連接配接和右連接配接)。

對于inner join就不存在這種情況,無論你的條件是寫在where後面還是on後面都是一樣的,但是還是建議寫在where後面。

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

1.謂詞類型與字段類型不一緻

SQL Server 容易忽略的錯誤

由于定義表的phone字段類型是字元型,而上面的查詢條件phone寫成了整形,導緻執行計劃走了索引掃描,且執行計劃select也有提示。

 2.謂詞類型與字段類型一緻

SQL Server 容易忽略的錯誤

      第二種查詢phone謂詞類型與字段類型一緻,是以查詢走了索引查找

在日常的語句編寫過程中需要注意這類問題,這将直接影響性能。

避免使用長位元組字段排序

SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤
SQL Server 容易忽略的錯誤

上面的語句查詢結果是一樣的,隻是寫法不一樣,O.create_date是表的建立時間而object_id 是一個自增值根據兩者的倒序排序得到的結果是一樣的,但是二者的執行效率卻不一樣。無論是從執行時間還是執行計劃明顯是後者的效率要好,從執行計劃可以看出後者的不需要進行排序操作因為object_id 本身就是排序好的,而且object_id 是整形而create_date是時間類型,如果是兩個大表進行連接配接操作再進行排序效率更明顯甚至前面用時間排序還可能查詢很久不出來。

總結

後面收集到類似的問題會補充在文章的末尾,文章持續更新中....,歡迎關注讨論。

本文轉自pursuer.chen(陳敏華)部落格園部落格,原文連結:http://www.cnblogs.com/chenmh/p/3999475.html,如需轉載請自行聯系原作者