朋友傳來的一個悲劇討論,大意就是進行更新時沒有下 WHERE 導致全部的資料都被更新,在 MS SQL 內可以在重點 Table 上,利用 instead of Trigger 來避免這種悲劇
利用 instead of Trigger 禁止一筆資料以上的更新或刪除,下面為 Script
星期五, 12月 27, 2013
星期一, 12月 23, 2013
[SSRS] 格式化條件 - 顯示圖片
網友問題,要分析逗號字串資料,並依資料內容來顯示所屬欄位圖形,如下圖
DataSet T-SQL
報表設計
DataSet T-SQL
CREATE TABLE FormatImage (Data varchar(10))
INSERT INTO FormatImage VALUES
('S,O,F,C'),
('S,O'),
('O,F,C'),
('S,O,C'),
('O,C'),
('C')
報表設計
先利用精靈拉出一個簡單的 Table 並新增 SOFC 四欄位
針對 S 欄位插影像控件
影像控件 => 滑鼠右鍵 => 影像屬性 => 一般,選擇事先建立號的[勾圖形],並內嵌在報表中就好
把圖片內嵌在報表中之後,就可以在[報表資料]=> 影像 中,看見剛剛的[勾圖形]
影像控件 => 滑鼠右鍵 => 影像屬性 => 可見性,點選[fx]button 來設定顯示條件
利用 indexof 來判斷 Data 中有是否有 "S" 字樣,有的話則顯示 S 欄位的勾圖形
依序完成 OFC 欄位條件設定
第二次插入影像控件,就不需要再進行匯入,直接選取[勾圖形]即可
預覽設定結果
看見預覽結果,根據 VFP 製作報表經驗,只要把背景設定為 Transparent 就可以解決此問題,沒想到 SSRS 影像控件中,根本就沒有 Transparent 設定,>.<
利用矩形包覆影像控件來達到 Transparent 效果
重新設定 SOFC 欄位內的控件,先插入矩形,並在矩形中再插入影像控件,影像控件設定跟之前是完全一樣的,下圖為完成 SOFC 欄位設定後的版面
預覽設定結果
針對 S 欄位插影像控件
影像控件 => 滑鼠右鍵 => 影像屬性 => 一般,選擇事先建立號的[勾圖形],並內嵌在報表中就好
把圖片內嵌在報表中之後,就可以在[報表資料]=> 影像 中,看見剛剛的[勾圖形]
影像控件 => 滑鼠右鍵 => 影像屬性 => 可見性,點選[fx]button 來設定顯示條件
利用 indexof 來判斷 Data 中有是否有 "S" 字樣,有的話則顯示 S 欄位的勾圖形
= IIF((Fields!Data.Value).indexof("S") > -1 , false , true)
依序完成 OFC 欄位條件設定
第二次插入影像控件,就不需要再進行匯入,直接選取[勾圖形]即可
預覽設定結果
看見預覽結果,根據 VFP 製作報表經驗,只要把背景設定為 Transparent 就可以解決此問題,沒想到 SSRS 影像控件中,根本就沒有 Transparent 設定,>.<
利用矩形包覆影像控件來達到 Transparent 效果
重新設定 SOFC 欄位內的控件,先插入矩形,並在矩形中再插入影像控件,影像控件設定跟之前是完全一樣的,下圖為完成 SOFC 欄位設定後的版面
預覽設定結果
星期五, 12月 20, 2013
[SQL] 觀看執行計畫重點
執行計畫可能會很龐大,要每個路徑都去觀察是一件相當費時的事情,從效能調校角度來觀察的話,可以先開啟 SET STATISTICS IO ON 來了解 Logical Read 最高是發生在哪一個 Table,先針對執行計畫內該 Table 相關執行路徑去觀察;利用 SET SHOWPLAN_ALL ON 改成文字執行計畫,複製至記事本上,再用 Ctrl + F 去搜尋該 Table 並觀察相關路徑也是一個方法,以下列出常見的觀察重點:
1. 減少資料量:
執行計畫中的箭頭符號代表資料量,資料量越大,箭頭會越粗,滑鼠移到箭頭上方會出現明細資料,可以觀察是否沒有適合的 WHERE 條件而抓取太多資料出來處理
2. 統計資訊老舊
觀察 operator 上的[實際資料列數量]和[估計的資料列數量]是否差異太大,差異太大代表,表示統計資訊需要更新
3. Index 使用方式是否合理
Index 使用有兩種方式:Index Seek 或 Index Scan,理論上使用 Index Seek 效能會比 Index Scan 佳,但假如抓取大量資料,利用 Index Scan 反而會比 Index Seek 更佳
4. 書籤查詢(Bookmark lookup)、鍵查詢(Key Lookup )
SQL 2005 SP2 開始 Bookmark lookup 更名為 Key lookup,代表 T-SQL 語法沒有滿足 covering index,可以觀察 T-SQL 是否有抓取多餘欄位資料或建立包含索引來避免
5. missing index
在 SSMS 內執行 T-SQL 語法,假如有 missing index 的話,會利用綠色文字來說明,在綠色文字說明上,點選滑鼠右鍵 => 遺漏索引詳細資料,就會建立 missing index 語法
Index 使用有兩種方式:Index Seek 或 Index Scan,理論上使用 Index Seek 效能會比 Index Scan 佳,但假如抓取大量資料,利用 Index Scan 反而會比 Index Seek 更佳
SQL 2005 SP2 開始 Bookmark lookup 更名為 Key lookup,代表 T-SQL 語法沒有滿足 covering index,可以觀察 T-SQL 是否有抓取多餘欄位資料或建立包含索引來避免
在 SSMS 內執行 T-SQL 語法,假如有 missing index 的話,會利用綠色文字來說明,在綠色文字說明上,點選滑鼠右鍵 => 遺漏索引詳細資料,就會建立 missing index 語法
6. 避免平行處理
OLPT 小交易系統,跑出平行處理通常代表耗能警訊,下左圖執行計畫中的 operator 上有黃色方向左雙箭頭在上面,就代表平行處理7. 排序
盡量避免在 SQL Server 中進行排序
星期一, 12月 16, 2013
[SSRS] 使用 Split 分割字串
被論壇問題誤導,此篇變成練習 SSRS 中利用 VB.NET Split 來分割逗號字串資料
DataSet T-SQL 語法
DataSet T-SQL 語法
CREATE TABLE SplitData (Data varchar(10))
INSERT INTO SplitData VALUES
('1,2,3,4'),
('1,2,3,'),
('1,2,,'),
('1,,,'),
('1,,4'), -- 不滿足四位
('2,4') -- 不滿足四位
星期五, 12月 13, 2013
[SQL] 具有內含資料行的索引
Nonclustered index 是由 Index Key、included column 和 Clustered Key 組成,利用 Nonclustered index 搜尋資料,會先利用 Index Key 來搜尋,假如利用 Index Key 就搜尋完全部資料,此情況稱為 Covering Index(覆蓋索引);相反地,無法在 Index Key 上找到全部資料,就會進一步利用 Clustered Key 進入 Clustered Index 內去搜尋所需要資料,此行為稱為索引鍵查閱(Key Lookup),2005 SP2 之前稱為書籤查詢(Bookmark Lookup),會增加鎖定和執行時間
建立[具有內含資料行的索引](文內簡稱包含索引)來滿足 Covering Index 進而消除 Key Lookup 來提高效能,就是此篇文章要說明的
建立包含索引的簡易語法
把滑鼠移到[索引鍵查閱]上,會顯示下列資訊,可以觀察到是為了要找 CustomerID 資料(綠色框框),所以利用[索引鍵查閱](紅色框框)進入PK_SalesOrderHeader_SalesOrderID (綠色框框)抓取資料
Key Lookup 只會利用 Nested Loop 來抓取資料,是一個極耗成本的動作,是進行 Perfomance Tuning 時的觀察重點,而除了建立包含索引來避免,撰寫 T-SQL 語法時,也要避免抓出不必要的資料,SELECT * 的寫法更是大忌喔
建立[具有內含資料行的索引](文內簡稱包含索引)來滿足 Covering Index 進而消除 Key Lookup 來提高效能,就是此篇文章要說明的
建立包含索引的簡易語法
CREATE INDEX IndexName
ON SchemaName.TableName (Col1,Col2,Col3.......)
INCLUDE (ColA,ColB,ColC.......)
利用 AdventureWork 的 Sales.SalesOrderHeader 來說明-- Step 1:針對 OrderDate 建立 nonclustered index
CREATE INDEX IX_OrderDate ON [Sales].[SalesOrderHeader] (OrderDate)
-- Step 2:找出 OrderDate = '20040729' 的 SalesOrderID、OrderDate 和 CustomerID 這三個欄位資料
SELECT
SalesOrderID ,
OrderDate ,
CustomerID
FROM [Sales].[SalesOrderHeader]
WHERE OrderDate = '20040729'
下圖為 Step 2 執行計畫,可以看出因為 IX_OrderDate 無法滿足 Covering Index 所以利用 Clustered Index 搭配 Nested Loop(巢狀迴圈)一筆一筆資料進入PK_SalesOrderHeader_SalesOrderID 抓取資料把滑鼠移到[索引鍵查閱]上,會顯示下列資訊,可以觀察到是為了要找 CustomerID 資料(綠色框框),所以利用[索引鍵查閱](紅色框框)進入PK_SalesOrderHeader_SalesOrderID (綠色框框)抓取資料
-- Step 3:刪除 IX_OrderDate
DROP INDEX IX_OrderDate ON [Sales].[SalesOrderHeader]
-- Step 4:建立包含索引
CREATE INDEX IX_OrderDate
ON [Sales].[SalesOrderHeader] (OrderDate)
INCLUDE (CustomerID) -- 包含 CustomerID 欄位
-- Step 5:再次執行查詢語法
SELECT
SalesOrderID ,
OrderDate ,
CustomerID
FROM [Sales].[SalesOrderHeader]
WHERE OrderDate = '20040729'
下圖為 Step 5 執行計畫,可以觀察到因為 CustomerID 已經包含在 IX_OrderDate 內,不再需要[索引鍵查閱]去搜尋資料Key Lookup 只會利用 Nested Loop 來抓取資料,是一個極耗成本的動作,是進行 Perfomance Tuning 時的觀察重點,而除了建立包含索引來避免,撰寫 T-SQL 語法時,也要避免抓出不必要的資料,SELECT * 的寫法更是大忌喔
- 2011 SQL Hero
星期五, 12月 06, 2013
[SQL] Partition Function
Partition Function 會指定如何分割資料表或索引並將資料對應到單一 Partition,建立 Partition Funcation,要決定
- DataType:資料型態必須和 Partition Column 的資料型態一致
- Boundary Value:資料界限值
- Range Left、Range Right:資料界限值是屬於 Boundary Value 的左邊還是右邊的 Partition