星期四, 12月 30, 2021

GodexRT 730X - 標籤機 Driver

同事告知剛上線 PC 在標籤列印上有異常,使用者告知標籤跑版,直接列印觀察,發現是解析度異常

在標籤機設定內,發現最大解析度只有 203 dpi,查詢其他正常列印 PC 設定值,300 dpi 才是正常值
 
GodexRT730X - 標籤機 Driver-1

203 dpi VS 300 dpi 測試列印差異

GodexRT730X - 標籤機 Driver-2

最後改安裝舊版 Driver 才解決 dpi 異常問題

星期四, 12月 23, 2021

[SQL] 索引維護成本

透過執行計畫來觀察 Insert、Update、Delete 時索引維護情況

建立範例資料
USE [AdventureWorks2019]
GO

DROP TABLE IF EXISTS [dbo].[EmployeeWithIndex]
DROP TABLE IF EXISTS [dbo].[Employee]

CREATE TABLE [dbo].[EmployeeWithIndex]
(
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[FullName] [nvarchar](100) NULL,
	[HireDate] [date] NULL,
	CONSTRAINT [PK_EmployeeWithIndex] PRIMARY KEY CLUSTERED ( [ID] ASC)
) 
GO

-- 建立該索引來觀察
CREATE INDEX IX_EmployeeWithIndex_FullName ON EmployeeWithIndex (FullName)
GO

CREATE TABLE [dbo].[Employee]
(
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[FullName] [nvarchar](100) NULL,
	[HireDate] [date] NULL,
	CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED ( [ID] ASC)
) 
GO

Insert 觀察

Insert 語法
INSERT INTO EmployeeWithIndex (FullName , HireDate)
	VALUES(N'張三' , '20211223')

INSERT INTO Employee (FullName , HireDate)
	VALUES(N'張三' , '20211223')
從執行計畫成本比較可以看出 EmployeeWithIndex 成本因為要更新 IX_EmployeeWithIndex_FullName 所以成本較高

 
[SQL] 索引維護成本-1

從叢集索引插入 operator 內可以看見 EmployeeWithIndex Insert 時有更新 IX_EmployeeWithIndex_FullName

     [SQL] 索引維護成本-2 - 複製
Update 觀察

Update 語法
UPDATE EmployeeWithIndex SET FullName = N'張三 Update' WHERE ID = 1
UPDATE Employee SET Hiredate = '20211224' WHERE ID = 1
更新時跑不同執行計畫,單純閱讀執行計畫差異


[SQL] 索引維護成本-3

從叢集索引更新 operator 內可以看見 EmployeeWithIndex Insert 時有更新 IX_EmployeeWithIndex_FullName

     [SQL] 索引維護成本-4

Delete 觀察

Delete 語法
DELETE FROM EmployeeWithIndex WHERE ID = 1
DELETE FROM Employee WHERE ID = 1
從執行計畫成本比較可以看出 EmployeeWithIndex 成本因為要更新 IX_EmployeeWithIndex_FullName 所以成本較高

[SQL] 索引維護成本-5


從叢集索引刪除 operator 內可以看見 EmployeeWithIndex Insert 時有更新 IX_EmployeeWithIndex_FullName
 
[SQL] 索引維護成本-6

星期四, 12月 16, 2021

[SQL] 備份權限

測試環境上在 SQL Server Agent 執行排程備份時失敗,錯誤訊息如下
訊息 以下列使用者的身分執行: NT SERVICE\SQLAgent$SQL2019

無法開啟備份裝置 'D:\SQLBackup\AdventureWorks2019.bak'。作業系統錯誤 5(存取被拒。)。 [SQLSTATE 42000] (錯誤 3201) BACKUP LOG 正在異常結束。 [SQLSTATE 42000] (錯誤 3013)

步驟失敗。
該錯誤訊息解讀沒有目的地資料夾權限,仔細看發現是透過 Agent 服務帳號執行,但印象中備份應該是 SQL Server 服務帳號來執行才是。

在文章
提到要授予 SQL Server 服務帳號,目的資料夾的完整權限,測試後確認是 SQL Server 服務帳號


[SQL] 備份權限

星期一, 12月 13, 2021

[SQL] 維護計畫 - 檢查資料庫完整性

在 [SQL] DBCC CheckDB 發信通知 內是直接寫語法來偵測 DBCC CheckDB 是否有偵測異常,有就發信通知,該篇使用 [維護計畫 - 檢查資料庫完整性] 來達到相同效果,紀錄相關重點

定義資料庫檢查完整性工作

[包含索引] 和 [僅限實體] 為預設勾選項目

[SQL] 維護計畫 - 檢查資料庫完整-7
  • 包含索引:檢查所有的索引頁面以及資料表資料頁面的完整性
  • 僅限實體:將檢查限制於頁面實體結構、記錄標頭的完整性,以及資料庫配置的一致性。 使用此選項可縮短 DBCC CHECKDB 對大型資料庫的執行階段,因此,建議您在實際系統上經常使用
  • Tablock:使 DBCC CHECKDB 取得鎖定,而不使用內部資料庫快照集。 這包括資料庫上的短期獨佔 (X) 鎖定。 使用此選項可協助 DBCC CHECKDB 在大量負載的資料庫上執行得快一些,但 DBCC CHECKDB 執行時,資料庫可用的並行處理能力會降低
  • 平行處理原則的最大程度:使用維護計畫精靈 內雖然沒有說明,但這很明顯是 DBCC CheckDB 執行時,可以限制 CPU 使用

選取報表選項

預設為 [將報表寫入文字檔],在這邊改以 [以電子郵件傳送報表] 為主,收件者為事先設定好的 operator

[SQL] 維護計畫 - 檢查資料庫完整-8

假如沒有事先設定 operator 的話,勾選 [以電子郵件傳送報表] 時,會出現下面訊息 [系統沒有定義運算子],運算子就是 operator,這翻譯很有問題,好歹也應該是 [操作員] 才是

[SQL] 維護計畫 - 檢查資料庫完整-15

執行維護計畫

因為設定發信,所以檢查完畢後,會發信通知 operator

[SQL] 維護計畫 - 檢查資料庫完整-11

參考該篇 - [SQL] 模擬資料庫毀損 破壞 AdventureWorks2017,再次執行維護計畫,發出的 Email 訊息內,有包含 DBCC CheckDB 內的檢查訊息,特別把錯誤訊息抓出來
失敗:(-1073548784) 執行查詢 "DBCC CHECKDB(N'AdventureWorks2017')  WITH  PHYSICA..." 失敗,發生下列錯誤: "資料表錯誤: 物件識別碼 1893581784,索引識別碼 1,分割區識別碼 72057594049200128,配置單位識別碼 72057594056933376 (類型 In-row data),頁面 (1:12640)。測試 (IS_OFF (BUF_IOERR, pBUF->bstat)) 失敗。值為 133129 和 -4。

物件識別碼 1893581784,索引識別碼 1,分割區識別碼 72057594049200128,配置單位識別碼 72057594056933376 (類型 In-row data): 頁面 (1:12640) 無法處理。請參閱其他錯誤以取得詳細資料。

DBCC 對 'AdventureWorks2017' 的結果。CHECKDB 發現了資料表 'HumanResources.Employee' (物件識別碼 1893581784) 中 0 個配置錯誤和 2 個一致性錯誤。CHECKDB 發現了資料庫 'AdventureWorks2017' 中 0 個配置錯誤和 2 個一致性錯誤。

repair_allow_data_loss 是 DBCC CHECKDB (AdventureWorks2017) 所發現之錯誤的最小修復層級。DBCC 的執行已經完成。如果 DBCC 印出錯誤訊息,請連絡您的系統管理員。"。

可能的失敗原因: 查詢發生問題、未正確設定 "ResultSet" 屬性、未正確設定參數,或未正確建立連接。
Email 截圖

[SQL] 維護計畫 - 檢查資料庫完整-13

檢視 T-SQL 選項

建立完成後可以進修改,可以看見 DBCC CheckDB 設定選項,會多出現一個 [檢視 T-SQL] 按鈕 

  [SQL] 維護計畫 - 檢查資料庫完整-18

產生的 TSQL 執行語法
use [AdventureWorks2017];
GO
DBCC CHECKDB(N'AdventureWorks2017')  WITH  PHYSICAL_ONLY  

報表與紀錄

SSMS 上圖示

       [SQL] 維護計畫 - 檢查資料庫完整-20

該介面內較特別之處在於多出 [紀錄] 選項

[SQL] 維護計畫 - 檢查資料庫完整-21
  • 紀錄擴充資訊:在記錄檔中包含更多資訊。 包含此選項會增加預存維護計畫記錄的大小。白話說明就是會記錄執行計畫使用的 TSQL 語法,此為預設勾選選項
  • 記錄到遠端伺服器:將維護計畫記錄記錄到遠端伺服器

紀錄擴充資訊範例

[SQL] 維護計畫 - 檢查資料庫完整-22

星期四, 12月 09, 2021

[ZWCAD] 缺少 SHX 檔案

在新電腦上重新安裝 ZWCAD 2018,使用者回報出現缺少字型,在官方文件 - 開啟圖檔常有字體shx找不到的狀況,或是圖面都是問號? 上發現解決方式,記錄一下

使用者回報缺少 SHX 檔案訊息

[ZWCAD] 缺少 SHX 檔案-1

該訊息有明確指出,缺少 chineset.shx 字型

[ZWCAD] 缺少 SHX 檔案-2

下載官方連結提供的字型檔案,並放進 ZWCAD fonts 資料夾內就行

[ZWCAD] 缺少 SHX 檔案-3

星期日, 12月 05, 2021

[SQL] 資料庫狀態

該篇紀錄 資料庫狀態 在 DB 上的顯示,文件上以英文為主,但因為安裝中文版,了解資料庫狀態在翻譯上對應,Online 和 Recovering 這兩個狀態不會在 DB 上看見,無法記錄喔

常常把 Recovery (復原) 和 Restore (還原) 混淆,才起心動念紀錄一下

狀態:Offline   

[SQL] 資料庫狀態-Offline

狀態:Restoring


[SQL] 資料庫狀態-Restoring

狀態:Recovery_Pending


[SQL] 資料庫狀態-Recovery_Pending

狀態:Suspect

[SQL] 資料庫狀態-Suspect

狀態:Emergency

星期六, 11月 27, 2021

[SQL] 還原至某時間點

被告知要救回誤刪資料,透過在測試機上還原至某時間點後,再從測試機把資料更新至正式機上,該篇紀錄還原至特定時間點作法

建立 Lab 環境
use AdventureWorks2017
go 

-- Step1:建立 tblRestore
CREATE TABLE [dbo].[tblRestore](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[InsertDateTime] [datetime] NULL,
	CONSTRAINT [PK_tblRestore] PRIMARY KEY CLUSTERED 
	( [ID] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

-- Step2:新增 5 筆資料
INSERT INTO tblRestore (InsertDateTime) VALUES(getdate())
GO 5

-- Step3:進行完整備份
BACKUP DATABASE AdventureWorks2017 TO DISK = N'D:\RestoreDemo.bak'

-- Step4:間隔一段時間,再新增 5 筆資料
INSERT INTO tblRestore (InsertDateTime) VALUES(getdate())
GO 5

-- Step5:進行第一次交易備份
BACKUP LOG AdventureWorks2017 TO DISK = N'D:\RestoreDemo.bak'

-- Step6:刪除全部資料,並記錄刪除時間 2021-11-26T23:15:35.0595818+08:00
DELETE FROM tblRestore

-- Step7:進行第二次交易備份
BACKUP LOG AdventureWorks2017 TO DISK = N'D:\RestoreDemo.bak'

-- Step8:透過語法來確定 bak 檔案內容
RESTORE HeaderOnly FROM DISK = N'D:\RestoreDemo.bak'
用 RESTORE HeaderOnly 可以查詢 bak 內的備份紀錄,下圖則使用 SSMS 還原功能,把備份紀錄從 bak 內顯示出來,方便閱讀

[SQL] 還原至某時間點-1

還原流程

筆記就沒有進行結尾備份,直接下參數 replace 處理囉
use master
GO

-- Step1:切換單人模式
ALTER DATABASE AdventueWorks2017 SET SINGLE_USER WITH ROLLBACK IMMEDIATE

-- Step2:還原 File = 1 完整備份
RESTORE DATABASE [AdventureWorks2017] FROM DISK = N'D:\RestoreDemo.bak'
	WITH FILE = 1 , 
		NORECOVERY , 
		REPLACE

-- Step3:還原 File = 2 第一次交易備份
RESTORE DATABASE [AdventureWorks2017] FROM DISK = N'D:\RestoreDemo.bak'
	WITH FILE = 2 , 
		NORECOVERY

-- Step4:還原 File = 3 第二次交易備份,並指定還原時間點
RESTORE DATABASE [AdventureWorks2017] FROM DISK = N'D:\RestoreDemo.bak'
	WITH FILE = 3 , 
		RECOVERY , 
		STOPAT = '2021-11-26 23:15:00'

-- Step5:切換多人模式
ALTER DATABASE [AdventureWorks2017] SET MULTI_USER WITH ROLLBACK IMMEDIATE
查詢 Table 內資料就可以看見全部資料都回來囉

  [SQL] 還原至某時間點-2

官方文件範例

官方文件上,看見下圖範例,觀念上是最後一個 Log 才指定 stopat 參數並進行 recovery,測試該範例用法,是每一個 Log 都指定 stopat 參數,一樣能夠正常還原的
 
[SQL] 還原至某時間點-3

星期五, 11月 26, 2021

[SQL] 1032 錯誤

在測試環境中發現事件檢視器內有 ESENT 相關錯誤訊息,只要 SQL Server 2019 服務重啟就會產生

[SQL] 1032 錯誤-1

事件 455
sqlservr (3628,R,98) SoftwareUsageMetrics-Api: 當開啟日誌檔案 C:\Windows\system32\LogFiles\Sum\Api.log 時,錯誤-1032 (0xfffffbf8) 發生。
[SQL] 1032 錯誤-2

事件 490
sqlservr (6520,R,98) SoftwareUsageMetrics-Api: 嘗試開啟檔案 "C:\Windows\system32\LogFiles\Sum\Api.chk" 供讀 / 寫存取失敗並出現系統錯誤 5 (0x00000005): "存取被拒。 "。 開啟檔案作業將會失敗並出現錯誤 -1032 (0xfffffbf8)。
[SQL] 1032 錯誤-3

在 Windows Server 2012 的應用程式記錄中的錯誤1032訊息 內有找到解決方式,只要在 \Windows\System32\LogFiles\Sum 內加入 SQL Server 服務啟動帳號讀寫權限就行

[SQL] 1032 錯誤-4

星期四, 11月 25, 2021

[Win] 設定自動更新

紀錄關閉 Windows Server 2019 Windows Update 自動下載更新的設定 

本機群組原則 => 電腦設定 => 系統管理範本 => Windows 元件 => Windows Update => 設定自動更新

[Win] 設定自動更新-1

把 [設定自動更新] 停用

[Win] 設定自動更新-3

在 Windows Update 內就可以看見 [您的組織已經關閉自動更新] 字樣的文字說明

[Win] 設定自動更新-2

星期三, 11月 24, 2021

[SQL] 備份成功紀錄

開啟 MS SQL 錯誤紀錄檔,會看到滿滿備份成功紀錄,錯誤紀錄檔案內重點,應該放在錯誤訊息的紀錄,因此透過 Trace flag 3226 關閉備份成功訊息紀錄,開啟後只會紀錄備份失敗訊息

[SQL] 備份成功紀錄-1

Trace flag 3226 說明
By default, every successful backup operation adds an entry in the SQL Server error log and in the system event log. If you create very frequent log backups, these success messages accumulate quickly, resulting in huge error logs in which finding other messages is problematic.

With this trace flag, you can suppress these log entries. This is useful if you are running frequent log backups and if none of your scripts depend on those entries.
在啟動參數內新增 3226,請輸入 [-T 3226]

[SQL] 備份成功紀錄-2

[SQL] 備份成功紀錄-3

最後可以透過 DBCC TracesStatus 來查詢 Trace Flags 的狀態,下列語法列出所有針對目前工作階段而啟用的 Trace Flags

星期日, 11月 21, 2021

[SQL] Nested Loops Join

Join 有三種主要演算法,分別為 Nested Loops、Merge Join 和 Hash Join,該篇紀錄 Nested Loops 相關

閱讀 Nested Loops 要先了解 Outer Table (執行計畫上方) 和 Ineer Table (執行計畫下方) 運作方式,會先從 Outer Table 取出一筆符合篩選條件資料後,去 Inner Table 內尋找符合篩選條件的資料,從程式角度來看,像是從 Outer Table 跑 foreach, 一筆一筆進 Inner Table 內把對應篩選資料抓出來

下面兩張圖為 [TSQL] 和 [執行計畫] Outer Table 和 Inner Table 對應,Outer Table 和 Inner Table 要從執行計畫去觀察,無法從 TSQL 得知,TSQL 圖片只是方便對應了解 



另外一個常見的 Nested Loops 情況就是 Key Lookup,當 nonclustered index 沒有辦法滿足所需資料,就會透過 Nested Loops 跑 Key Lookup 去取回所需資料
SELECT * 
FROM Person.Person
WHERE LastName = 'Duffy'

觀察 Nested Loops 要注意 Outer Table 資料量,基本上會希望 Outer Table 要從資料量小的開始,Turning 時剛好發現一個案例,Outer Table 資料量大於 Inner Table

星期四, 11月 18, 2021

[SQL] Service Pack

最近要升級為 SQL Server 2019 才注意到,原來 Service Pack 更新在 SQL Server 2017 開始就沒有了,只會有 Cumulative Updates (CUs) 和 critical updates (GDRs) 這兩種更新,詳見該文章 - KB4041553 - SQL Server Service Packs are discontinued starting from SQL Server 2017

下圖出處為 適用於 Microsoft SQL Server 的最新更新

[SQL] Service Pack

星期三, 11月 17, 2021

[VFP] UseCursorSchema

跟同事討論的 Cursor Schema 欄位名稱是以哪個設定為主,在 CursorAdapter 內各有一種設定和
一種呼叫方式,分別為

CursorAdapter.UseCursorSchema,下圖紅框 [Use CursorSchema when filling cursor] 即是
CursorAdapter.CursorFill() 時的第一參數


測試範例為下圖,把 Col2 名稱改為 ColName,並同時測試上述兩種方式

loDemo = CreateObject("VCXName.caDemo")
lbDemo = loDemo.CursorFill(.T.) // 第一參數 lUseCursorSchema 為 .T.
IF lbDemo = .F.
	AERROR(laError)
	MESSAGEBOX(laError(2))
ELSE 
	SELECT Demo
	BROWSE
ENDIF 

從下圖可以看見 Cursor 欄位名稱為 ColName

星期六, 11月 13, 2021

[C#] TreeView - 更新閃爍情形

遇上 TreeView 更新時發生閃爍 (Flicker) 情況,應用情境是把使用者權限總表用 TreeView 畫出,之後每位使用者把擁有權限的 TreeNode.Checked 打勾並 Hightlight 顯示,一開始想說有開啟 DoubleBuffer 也有使用 BeginUpdate()、EndUpdate() 來進行 TreeView 更新,查發現原來更新 TreeViewNode.Checked 和 Hightlight 時,並沒有使用到 BeginUpdate()、EndUpdate() 也才發現閃爍情況原來也有差異

Setting the DoubleBuffered property does not affect the TreeView control. If you want to reduce flicker when the TreeView is drawn, use the BeginUpdate and EndUpdate methods.

情況一:沒有應用上 BeginUpdate()、EndUpdate()

可以從下圖發現,TreeView 會一直閃爍且 ScrollBar 會上下跑

情況二:使用 BeginUpdate()、EndUpdate()

this.BeginUpdate();
// 填入 TreeNode.CheckBox 並 Highlight
this.EndUpdate();
可以從下圖發現,TreeView 只會閃一下

情況三:禁止清除背景訊息

protected override void WndProc(ref Message m)
{
	if (m.Msg ==  0x0014) // 禁止清除背景訊息,也可以查關鍵字 WM_ERASEBKGND
		return;

	base.WndProc(ref m);
}
可以從下圖發現,TreeView 就完全不會閃爍