SQL Server 要避免的編程壞習慣

摘自 <SQL Server MVP Deep Dives Vol.2>sql

使用select *

  • 會返回不須要的列,增長磁盤和網絡開銷編程

  • 若是view的定義裏用了select *, 而底層的表有列名的變化的時候,view仍然會返回原來的列
IF OBJECT_ID('tb1') IS NOT NULL
DROP TABLE tb1
GO
CREATE table tb1(id int)
GO

IF OBJECT_ID('v1') IS NOT NULL
DROP VIEW v1
GO
CREATE view v1 
as
    select * from tb1
GO

select * from v1

--改表的定義,增長1列
ALTER TABLE tb1 ADD name sysname;

--仍然只返回id列,新加的name沒有返回
select * from v1

解決的方法是使用sys.sp_refreshsqlmodule刷新定義網絡

sys.sp_refreshsqlmodule 'v1'
--返回id, name兩列
select * from v1

將view定義爲SCHEMABINDING類型能夠阻止select *的使用,同時也會阻止底層table的schema的改動,若是須要改table的schema,就須要先drop view。函數

聲明變量varchar/nvarchar 不指定長度

有面向對象編程經驗的人可能習慣了使用string類型而不用定義長度,到了SQL裏面,這種習慣就會出問題code

DECLARE @x CHAR = 'foo';
SELECT a = @x, b = CAST('foo' AS CHAR), c = CONVERT(CHAR, 'foo');

結果以下:
a | b | c
--|---|--
f | foo | foo |對象

緣由是全部字符類型若是在聲明變量時若是沒有定義長度,那麼長度就是1.(這是遵循ANSI標準的),把上面代碼的char換成varchar,nvarchar也是同樣的結果。若是你用cast或者convert函數的話,長度是30.排序

若是你建立表的時候字符類型的列沒有指定長度,行爲也是同樣的,只能存1個字符串字符串

CREATE TABLE dbo.x(y VARCHAR);
GO
INSERT dbo.x(y) SELECT 'foo';

--結果
Msg 8152, Level 16, State 14, Line 2
String or binary data would be truncated.
The statement has been terminated.

若是sp的參數沒有定義長度,在傳參的過程當中就被偷偷截斷了string

CREATE TABLE dbo.x(y VARCHAR);
GO
CREATE PROCEDURE dbo.x_insert
     @y VARCHAR
AS
BEGIN
     SET NOCOUNT ON;
     SELECT @y;
END
GO
EXEC dbo.x_insert @y = 'foo';

--結果返回'f'

選擇合適的數據類型

常見的錯誤是不少人喜歡用字符類型來存時間,理由是能保存成想要的格式,不須要作格式轉換就能夠直接讀取到UI上. 這樣與使用日期類型作存儲比較,缺點是面向對象編程

  • 沒法驗證數據格式是否正確
  • 沒法對數據按照時間排序
  • 沒法使用日期相關的函數對數據進行處理

關於日期類型的查詢

使用>, <, 而不是between

關於order by的誤解

不少人覺得對一個有clustered index的table 進行查詢即便不指定order by也會按照clustered index的定義返回有序的數據集,這個假設是不成立的. 從執行計劃上是能夠看出來的

相關文章
相關標籤/搜索