星期二, 6月 29, 2021

[C#] SelectionRules

該篇是 [C#] 控件智能標籤 延續,加入 ControlDesigner.SelectionRules 說明。

SelectionRules 定義設定時期兩件事情
  • 控件縮放
  • 控件移動
該筆記紀錄控件縮放方框,在 ControlDesigner 內加入下面的 Code 來觀察
namespace UCControlDesignerExample
{
    public class ColorLabelControlDesigner : ControlDesigner
    {
        /// <summary>
        /// 控制項選擇規則
        ///     控件滑鼠移動 (SelectionRules.Moveable)
        ///     控件鍵盤移動 (SelectionRules.Visible)        
        ///     控件縮放 (SelectionRules.AllSizeable)
        /// </summary>
        public override SelectionRules SelectionRules
        {
            get { return SelectionRules.Moveable | SelectionRules.Visible; }
        }
    }
}
把控件截圖來觀察
  • 上圖:沒有進行任何設定,控件四周有拉取方框
  • 下圖:設定只能移動,控件四周沒有拉取方框
[C#] SelectionRules

控件能不能縮放還是看控件本身,不是有拉取方框就一定能縮放

星期六, 6月 12, 2021

[C#] Delegate - Method 使用

技術社群看到的 delegate 使用方式,直接拿 Func<T,TResult> Delegate 範例來記錄
using System;
using System.Linq;

namespace DelegateSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 定義一個 delegate 來進行字串轉換
            Func<string, string> FuncToUpper = str => str.ToUpper();

            // 定義字串陣列
            string[] words = { "orange", "apple", "Article", "elephant" };

            // 使用方法 1:直接丟進 Select 內跑並輸出
            words.Select(FuncToUpper).ToList()
                .ForEach(s => Console.WriteLine(s));

            // 使用方法 2:把 delegate 直接當成 Method 使用
            foreach (var w in words)
            {
                Console.WriteLine(FuncToUpper(w));
            }
        }
    }
}
該方式等於是把該 Method 內使用到的 Method 放在其中,不用在 Method 外建立一個 Method,整體可讀性增加不少

星期五, 6月 11, 2021

[SQL] Like - Constant Scan

[SQL] Like - 萬用字元 解決效能問題後,就一直在查資料了解 Constant Scan operator

固定掃描 (Constant Scan) 官方文件說明
固定掃描運算子會在查詢中加入固定的一或多列。計算純量運算子通常在固定掃描之後使用,以便將資料行加入固定掃描運算子所產生的資料列。
Constant Scan 只會用一筆資料來跑執行計畫,所以下圖流程基本上是固定的

[SQL] Like - Constant Scan

用一筆資料來跑執行計畫,感覺就是沒有統計資訊才有該現象,整理網路資料有兩個方向 

星期四, 6月 10, 2021

[SQL] Like - 結尾字元搜尋改善

該 [SQL] Like - 萬用字元 例子內之所以必須用 A_____12345 去進行搜尋,原因在於實務邏輯內,有個未完工單號可以利用後 5 碼來進行搜尋單號的設計,要滿足該需求並改善搜效能,可以利用計算欄位來產生後 5 碼資料欄位,AP 只要搜尋該欄位就行

因為單號是固定長度,所以直接用 RIGHT() 取後 5 碼就行
----- 建立計算欄位並建立索引
ALTER TABLE [派工] ADD LastNO5 AS RIGHT(派工單號 , 5) PERSISTED 
CREATE INDEX IX_派工_LastNO5 ON 派工 (LastNO5)

SELECT *
FROM 派工
WHERE LastNO5 = '後5碼單號'
觀察執行計畫
[SQL] Like - 結尾字元搜尋改善

星期三, 6月 09, 2021

[SQL] Foreign Key - Insert

[SQL] Foreign Key - Delete 觀察 Delete 的影響,這篇筆記觀察 insert 時 FK 存在與否的影響
USE tempdb
GO 

----- 建立 tblOrders、tblCustomer Table
DROP TABLE IF EXISTS tblOrders
DROP TABLE IF EXISTS tblCustomer

CREATE TABLE tblOrders (
			OrderID int Primary Key identity(1,1) , 
			CustomerID int)
CREATE TABLE tblCustomers (
			CustomerID int Primary Key identity(1,1), 
			CustomerName nvarchar(50))

----- 建立 tblCustomers 資料
INSERT INTO tblCustomers (CustomerName) VALUES
	(N'客戶1') , (N'客戶2') , (N'客戶3') , (N'客戶4') , (N'客戶5')
    
----- 沒有 FK - insert 資料並觀察執行計畫
INSERT INTO tblOrders (CustomerID) VALUES(1)

----- 建立 tblOrders、tblCustomers 之間的 Foreign Key
ALTER TABLE [dbo].[tblOrders] WITH CHECK ADD CONSTRAINT [FK_tblOrders_tblCustomers] FOREIGN KEY(CustomerID)
REFERENCES [dbo].[tblCustomers] (CustomerID)

----- 存在 FK - insert 資料並觀察執行計畫
INSERT INTO tblOrders (CustomerID) VALUES(2)

沒有 FK 時

對 tblOrders insert 資料,就單純看見 [叢集索引插入]
 
[SQL] Foreign Key - Insert-2

存在 FK 時

可以觀察到對 tblOrders insert 資料,會另外發動 Index Seek 去 tblCustomer 內確認,並在 assert 判斷是否違反 FK

星期一, 6月 07, 2021

[SQL] Foreign Key - Join Elimination

Turning 時發現過,假如有 JOIN Table 但是沒有 Select 該 Table 任何欄位,Query Optimizer 會排除該 Table,執行計畫內就不會出現,閱讀 Explore the secrets of SQL Server execution plans 後才發現,原來是因為 Foreign Key,所以 Query Optimizer 才能這樣判斷

FK_SalesOrderDetail_SalesOrderHeader 存在
SELECT 
	SOD.* -- 只 select Sales.SalesOrderDetail Table 欄位
FROM Sales.SalesOrderHeader AS SOH
	JOIN Sales.SalesOrderDetail AS SOD ON SOH.SalesOrderID = SOD.SalesOrderID
[SQL] Foreign Key - Join-1 

FK_SalesOrderDetail_SalesOrderHeader 不存在
-- 刪除 FK
ALTER TABLE Sales.SalesOrderDetail DROP CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader]
GO

SELECT 
	SOD.*
FROM Sales.SalesOrderHeader AS SOH
	JOIN Sales.SalesOrderDetail AS SOD ON SOH.SalesOrderID = SOD.SalesOrderID
[SQL] Foreign Key - Join-2

星期五, 6月 04, 2021

[SQL] 擴充事件 - 排除特定 DB

在 Product 環境上,有設定排程每天要把 DeadLock 相關資訊抓進自訂 Table 內保留,並發出 mail 來通知有 DeadLock 發生,該機制一上線就發現,每天都是 DataCollection DB 所產生的 DeadLock,因此在擴充事件 system_health 內,設定篩選條件來過濾掉

利用 sys.database 來查詢 database_id
SELECT 
	database_id , 
	[name]
FROM sys.databases
在 system_health 內設定篩選條件

[SQL] 擴充事件 - 死結 - 排除特定 DB-1

[SQL] 擴充事件 - 死結 - 排除特定 DB-2

把 system_health 轉成 Script 的話,在 xml_deadlock_report 內,就可以看見篩選條件
ADD EVENT sqlserver.xml_deadlock_report(
    WHERE ([sqlserver].[database_id]<>(7)))

星期三, 6月 02, 2021

[SQL] Like - 估計、實際資料

延續該筆記 - [SQL] Like - sp_executesql,平常確認派工相關商業邏輯時,都是依靠 [未結案非叢集索引] 來限制資料,心理一直有個執念,執行計畫就是要從它開始才是,所以有測試過下列方式企圖來改變
  • 強制指定 [未結案非叢集索引]  來跑,有點意外竟然沒有用
  • 加入條件來變化 SARG,有成功但執行計畫增加 1 %
WHERE 單號 like LIKE 'B_____12345%'
	AND 單號 > '' -- 加入該條件
改變後執行計畫
 
[SQL] Like - 估計、實際資料-3
Index Seek Operator
 
[SQL] Like - 估計、實際資料-1
從 operator 可以看到 Predicate 是 like 單號條件,但 Seek Predicate 是[單號大於空值]

  • 心血來潮用 Parameter Sniffering Local Variable,結果跑出很糟糕的統計數字和執行計畫
EXEC sp_executesql N'
	DECLARE @內部派工參數 AS char(11) = @外部派工參數
	DECLARE @內部結案參數 AS char(1) = @外部結案參數

	SELECT 欄位
	FROM 資料表名稱
	WHERE 單號 like @內部派工參數 + ''%'') 
		AND 是否結案 = @內部結案參數 )  '
	,N'@外部單號參數 char(11),@外部結案參數 char(1)'
	,@外部單號參數 = 'B_____12345'
	,@內部結案參數 = ''
以前沒有在看 operator 上的數字,有也是轉過去 Plan Explorer 上觀察,看哪一個 operator 被顯示為紅色,表示成本較高而以,這次是真的這破百數字太顯著引起注意,原來 SSMS 上會把 operator 的 [實際資料列數目] 和 [估計的資料列數目] 打在上面並計算出百分比 
實際資料列數目 / 估計的資料列數目 (9986 / 7063) = 141% ,表示實際數量遠大於估計數量
[SQL] Like - 估計、實際資料-2

星期二, 6月 01, 2021

[SQL] Like - sp_executesql

在 [SQL] Like - 萬用字元 整理完 TSQL 後,讓效能回歸正常情況,原本有期待執行計畫起始 operator 會從 [未結案非叢集索引] 開始跑,沒想到還是從 [固定掃描 (Constant Scan)] 開始。

找些 TSQL 來驗證後發現,sp_executesql + like 似乎都會從 [固定掃描 (Constant Scan)] 開始跑

TSQL Like 條件直接執行

從 [未結案非叢集索引] 開始跑,變數沒有參數化,[LIKE 'B_____12345%'] 資料被轉成 [大於等於 B 且小於 C]

[SQL] Like _ 萬用字元 - sp_executesql-2

sp_executesql + like

sp_executesql 參數化變數
  • 1 號 operator:有 LikeRangeStart、LikeRangeEnd、LikeRangeInfo 出現
  • 2 號 operator:透過 Nested Loops 去找 [未結案非叢集索引]
  • 3 號 operator:傳進的變數都參數化
[SQL] Like _ 萬用字元 - sp_executesql-1