0%

前言

在之前我有寫一篇關於資料庫的ACID分享RDBMS資料庫基本原則

假如我們系統是一個多執行續高併發系統也要注意Atomic不然會造成資料會有Data Racing導致bug產生..

本文使用範例在我github上CAS_Lock有興趣的人可以參考.

沒有注意Atomic會導致的問題

我是我們公司擔任技術面試官之一,假如面試者說他實作過高併發系統

我就會先問以下問題來辨別是否要更深入面試高併發系統相關問題.

下面Sample Code是這樣.

我用Task假裝高併發,下面有一個Member類別預設給100000元的Balance

有一個UpdateBalance每呼叫一次就扣10元,我透過For跑10000次

Read more »

前言

假如我跟你說下面語法在高併發系統,UserId = 101餘額會扣到變負值你們知道問題出在哪裡嗎?

本篇會跟大家解析問題所在(DB Isolation重要性)

建立樣本資料 & 問題解釋

我建立一個資料表UserAccount並建立一個PK在UserID欄位上,裡面Patch一筆資料Userid = 101餘額有100元

1
2
3
4
5
6
7
8
9
CREATE TABLE dbo.UserAccount(
UserID INT NOT NULL,
Balance DECIMAL NOT NULL
PRIMARY KEY (
UserID
)
);

INSERT INTO dbo.UserAccount VALUES (101,100);

執行扣款有bug版腳本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BEGIN TRAN
DECLARE @UserID INT = 101,
@Balance DECIMAL(18,4) = 1

IF EXISTS(
SELECT 1
FROM dbo.UserAccount
WHERE UserID = @UserID
AND Balance >= @Balance
)
BEGIN
UPDATE dbo.UserAccount
SET Balance = Balance - @Balance
WHERE UserID = @UserID
END

COMMIT TRAN

明明上面有使用Transatcion但為什麼還是會扣成負值?

壓力測試數值介紹 & 問題重現

Read more »

前文

現今越來越多系統使用MQ來達成非同步並來提升系統吞吐量,我今天想要介紹的是EasyNetQ一個封裝RabbitMq Client .net框架

  • 小型DI容器
  • 對於RabbitMq封裝
  • 對於連接使用lazy connection連接RabbitMq

If the server disconnects for any reason (maybe a network fault, maybe the RabbitMQ server itself has been bounced), EasyNetQ will revert to polling the endpoint until it can reconnect.

使用EasyNetQ來操作RabbitMq簡單很多,但在使用上有些地方需要注意

本篇會再跟大家分享

RabbitMq Client vs EasyNetQ程式碼比較

我會使用之前使用RabbitMq Client寫的範例利用EasyNetQ來改寫一次.

程式原始碼 Sample Code

Publisher程式碼

Read more »

前文

最近面試有一間公司要求使用Restcountries API使用CRUD前端Html串接API,有看我文章的夥伴應該知道我大多是研究後端或CI/CD相關技術,對於前端技術較少研究,這次我打算使用vue.js來完成此次需求.

需求如下

  1. 分頁
  2. 顯示國家相關資訊
  3. 排序效果
  4. 點選國家名稱進入Detail頁面

因為以上幾點都是CRUD相關操作,關於CRUD相關操作使用三大框架就很適合(所以我選擇使用Vue)

話不多說先給大家看看成品 RestcountriesSample

Source Code

要使用的API介紹

雖然官網對於API介紹雖少,但我相信只要有常串API的人應該可以很快猜出每個API作用.

  • All:請求所有國家資訊
  • FULL NAME:查找國家By名子.
Read more »

Heap 資料表

如果資料表沒有Clustered Index那此表就會是Heap資料表

Heap資料表有個特性是Insert資料快比較快,因為插入資料不需要考慮排序。

適合使用在Log資料表、Event資料表、稽核資料表….一直新增資料,但比較少查詢或更新的表

一般來說Heap資料表很少見,因為都會建議每張表都要有Clustered Index.

另外Heap資料表Data Page沒有像其他B+Tree Index有對於左右Page連結Reference.

Heap資料表中不得不知(forwarding pointer)

假如在Heap資料表更新欄位資料,就可能會造成forwarding pointer如果你資料表有許多forwarding pointer可能就要考慮是否要優化調整….

forwarding pointer會造成Logic read增加,因為在Heap讀取資料使用Allocation scan(依照儲存page順序讀取資料,讀到page有forwarding pointer就會多讀取資料頁)

forwarding pointer是因為原本Page(8KB)塞不下更新後資料就會先把資料搬到另一個新建立Page上並在原本Page建立一個類似指標東西指向它.

Read more »

前言:

使用DB新增欄位一般很快就可以執行完畢,但最近我們在prod新增一個bit欄位卻需要跑快45分鐘…

經後面追查找到原因才有本篇文章.

問題重現

下面語法會建立兩個Table.

  • Test:新增10,000,000筆Sample Data
  • TestSplit:新增1,000,000筆Sample Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
DROP TABLE IF EXISTS [dbo].[Test]

CREATE TABLE [dbo].[Test](
[ID] [int] NOT NULL IDENTITY(1,1),
[CustomerID] [VARCHAR](40) NOT NULL,
[col1] [VARCHAR](100) SPARSE NULL,
[col2] [VARCHAR](100) SPARSE NULL,
[col3] [VARCHAR](100) SPARSE NULL,
[col4] [VARCHAR](100) SPARSE NULL,
[CreateDate] [datetime2](3) NOT NULL,
) ON [PRIMARY]

CREATE UNIQUE CLUSTERED INDEX CIX_ID ON [dbo].[Test](ID)

INSERT INTO [dbo].[Test] ([CustomerID],Col1,Col2,Col3,Col4,[CreateDate])
SELECT TOP 10000000
REPLICATE('ABCD',10),
REPLICATE('A',100),
REPLICATE('B',100),
REPLICATE('C',100),
REPLICATE('D',100),
SYSDATETIME()
FROM sys.all_columns c1
CROSS JOIN sys.all_columns c2

DROP TABLE IF EXISTS [dbo].[TestSplit]

CREATE TABLE [dbo].[TestSplit](
[ID] [int] NOT NULL IDENTITY(1,1),
[CustomerID] [VARCHAR](40) NOT NULL,
[col1] [VARCHAR](2000) SPARSE NULL,
[col2] [VARCHAR](2000) SPARSE NULL,
[col3] [VARCHAR](2000) SPARSE NULL,
[col4] [VARCHAR](2000) SPARSE NULL,
[CreateDate] [datetime2](3) NOT NULL,
) ON [PRIMARY]

CREATE UNIQUE CLUSTERED INDEX CIX_ID ON [dbo].[TestSplit](ID)

INSERT INTO dbo.[TestSplit] ([CustomerID],Col1,Col2,Col3,Col4,[CreateDate])
SELECT TOP 1000000
REPLICATE('ABCD',10),
REPLICATE('A',2000),
REPLICATE('B',2000),
REPLICATE('C',2000),
REPLICATE('D',2000),
SYSDATETIME()
FROM sys.all_columns c1
CROSS JOIN sys.all_columns c2

我們先在test table新增欄位語法如下

執行下面語法瞬間完成

1
2
3
4
5
6
IF COL_LENGTH('dbo.[Test]','Col6') IS NULL
BEGIN
ALTER TABLE dbo.Test
ADD Col6 BIT NOT NULL
CONSTRAINT DF_Test_Col6 DEFAULT 0
END
Read more »

前言

稍微有經驗的.net工程師一定聽過或使用過Reflection,Reflection雖然好用(能動態處理很多事情)但對於效能會有些影響.

我能否擁有Reflection的動態彈性且兼顧效能呢?

有:就是我們這次要介紹的Expression.

Expression vs Reflection performace

我會準備一個範例來比較ExpressionReflection效能差異

  • Expression
  • Activator.CreateInstance

Activator.CreateInstance Code

Activator.CreateInstance沒甚麼好說就是一個靜態方法傳入Type動態產生一個物件

Expression code

Read more »

前言:

docker透過指令能快速建立相同執行環境並比起VM減少電腦資源消耗.

依照上面優點這就是為什麼docker可以在短時間內快速串紅.

上圖來源《Docker —— 從入門到實踐­》正體中文版

我在網路上找到很棒一個Docker操作流程圖,概括Docker操作時會用到的指令和動作關係.

因為外面有很多blog有對於Docker指令介紹本篇不著重在介紹指令,想要跟大家分享Docker其他細節.

關於Window中的Docker

如果我們需要在Prod運行一個系統可能需要許多不同的程式架構和語言才能完成(甚至有OS限制),在傳統我們選擇使用VM來幫建立不同環境來承載不同程式架構,但VM會模擬OS導致非常肥大,安裝使用資源較大,而Container的Image可以依照我們需求來客製我們需要核心並且Container可以宿主核心達到效能較佳的利用

在Window10 我們可以利用HyperV來跑Docker,原因是HyperV類似一個虛擬機幫我們模擬Linux並且運行Docker Daemon來控管docker container.

Docker需要在Linux中執行,Docker Daemon幫助Client透過命令來操作Docker,如果沒有Docker Daemon我們就無法執行Docker搂.

Read more »

前言

如果我們在Local或測試環境需要建立一個連接MSSQL環境,傳統需要安裝MSSQL和SSMS

但現在有一個更快速輕便方法,就是使用Docker建立MSSQL環境 + VSCode Extension充當SSMS.

安裝時間不僅更快且需要花的空間更小,且可以在Linux使用

Docker建立MSSQL

相信大家都有聽過Docker因為這篇是介紹如何運用Docker建立SSMS,這裡就不介紹太多Docker相關指令意思,有興趣可以自行google.

Window 10才支援docker,因為docker daemon需要在Linux上運作,window需要透過Hyper-V來虛擬化Linux.

如果你是使用Window我推薦下在Docker Desktop,使用UI呈現目前Container有的一些資訊.

如果下載並安裝完Docker可透過docker info命令可以查看,目前Docker使用資訊

Read more »

前文

隨著業務量增長,資料庫的複雜程度也會成正比增長

這裡跟大家分享一個好用壓測資料庫工具SqlQueryStress

在Dev可以模擬高併發時產生的問題,下面會分享我之前Prod遇到問題並解決問題過程

詳細資訊可以看SQLServer-Merge-condition-problem

SQLQueryStress介紹

在執行效能調教和測試高併發產生問題時,我們會關注幾個特別資訊

  1. CPU執行時間
  2. logical read數值
  3. Total執行時間

在此工具都有相對應的資訊提供給我們觀看

Read more »