由於對 Google sheet 內建函式不常用,但腦海總浮現之前查過的印象,還是記錄一下好了。


比較樣本數相同

比較兩欄的資料是否有差異,這邊可以直接用 =,如果需要判斷大小寫或確切數值,則可以用 EXACT

Way1: =A1=B1
Way2: =EXACT(A1,B1)

Column 1 Column 2 Equal Mark Exact()
AAA AAA TRUE TRUE
BBB BBB TRUE TRUE
CCC NotEQual FALSE FALSE
DDD ddd TRUE FALSE

比較樣本數量不同

=ArrayFormula(iferror(if(match(F2:F7,G2:G5,0),"FoundMatch","")))

Column 1 Column 2 Result
AAA AAA FoundMatch
BBB BBB FoundMatch
CCC NotEQual
DDD ddd FoundMatch
EEE
閱讀全文 »

由於對 Google sheet 內建函式不常用,但腦海總浮現之前查過的印象,還是記錄一下好了。


Group 測試數據:

GroupColumn CountColumn SumColumn
AAA 10 100
BBB 20 200
CCC 30 300
AAA 40 400

GroupColumn 進行 GroupBy 預期應該是:

GroupColumn CountColumn SumColumn
AAA 50 500
BBB 20 200
CCC 30 300

語法:

1
=QUERY(rawData!A1:C4,"select A, count(B), sum(C) group by A")
  • rawData 為 sheet 名稱
  • A1:C4 為資料範圍

如果想要替 Column 命名,需使用 label 語法,例如 label A 'AliasName'

閱讀全文 »

本文介紹改用 Lua 方式存取 Redis,以省下連線、存取次數。

Demo內容

  1. 先在 redis 建立一個 key
  2. 以 lua 方式執行,把值取出來,加上整數 123,寫回去 redis
  3. 以一般指令方式,把值取出來,加上整數 123,寫回去 redis

建立連線機制

1
2
3
4
5
private const string RedisHost = "127.0.0.1:6379";
private const string TestKey = "TestRedisKey";

using var conn = await ConnectionMultiplexer.ConnectAsync(RedisHost);
var redisDb = conn.GetDatabase();

一般存取方式

當有一些邏輯比較複雜就必須把值取回程式中運算。

1
2
3
4
5
6
7
8
9
10
11
12
private static async Task RunWithoutLua(IDatabase db)
{
var currentValue = await db.StringGetAsync(TestKey);

// Some complicated logic in C#
var newValue = Convert.ToInt32(currentValue) + 123;
await db.StringSetAsync(TestKey, newValue);

// Validate
var afterUpdatedValue = await db.StringGetAsync(TestKey);
Console.WriteLine($"RunWithoutLua: After updated value: {afterUpdatedValue}");
}

用 Lua 方式存取

這邊是示意才用這種方式寫,但大型專案還是建議把 .lua 整理起來分類放在資料夾內,這樣 repository 層比較乾淨,也不會有過多、複雜的邏輯。

閱讀全文 »

Docker-compose 設定檔注意事項 這篇文章的範例中,我們使用了 MongoDB 的容器。yml 如下:

1
2
3
4
5
6
7
8
version: '3'
services:
mongo-local-test.com:
image: mongo
container_name: mongodb_cotainer
ports:
- "27117:27017"
entrypoint: [ "/usr/bin/mongod","--bind_ip", "localhost,mongo-local-test.com"]

好處是每次開啟都是全新的,不用擔心資料弄髒弄壞,但如果想保留資料怎麼辦?這時候需要使用到 volumes 設定了。

1
2
volumes:
- '~/Desktop/mount-mongo-data:/data/db'

: 之前的是實體位置,之後的是 container 內的位置。

設定完後 docker-compose up / down 就可以看到實體檔案在該路徑上了。如下:

1
2
3
4
5
6
7
8
➜  mount-mongo-data ls
WiredTiger _mdb_catalog.wt index-1-6246240698095516127.wt mongod.lock
WiredTiger.lock collection-0-6246240698095516127.wt index-3-6246240698095516127.wt sizeStorer.wt
WiredTiger.turtle collection-2-6246240698095516127.wt index-5-6246240698095516127.wt storage.bson
WiredTiger.wt collection-4-6246240698095516127.wt index-6-6246240698095516127.wt
WiredTigerHS.wt diagnostic.data journal
➜ mount-mongo-data pwd
/Users/mingyi/Desktop/mount-mongo-data

總不可能每次都指定實體位置吧~這樣要維護也很困難,另一種方式就跟其他 container 的 voulume 一樣放置,語法如下:

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
volumes:
mongo-mount-data:

services:
mongo-local-test.com:
image: mongo:latest
container_name: mongo_latest
ports:
- "27117:27017"
volumes:
- mongo-mount-data:/data/db
閱讀全文 »

在使用 lua 的 unpack 語法一定要特別注意,如果已經知道參數的數量,那會強烈建議不要使用 unpack。

測試條件

  • 迴圈執行次數 一百萬
  • table 長度 5

選手一 unpack

1
2
3
4
5
local style1 = function()
for i=1, loopCount do
local v1,v2,v3,v4,v5 = table.unpack(table_a)
end
end

選手二 get value directly

1
2
3
4
5
6
7
8
9
local style2 = function()
for i=1, loopCount do
local v1 = table_a[1]
local v2 = table_a[2]
local v3 = table_a[3]
local v4 = table_a[4]
local v5 = table_a[5]
end
end

結果

1
2
elapsed: 75.28 ms  // style1: unpack
elapsed: 0.40 ms // style2

結論

閱讀全文 »

本文 sample code 可以改為 pass by function 方式更為簡潔,但之前文章就先不改動了。
可以參考這篇文章的寫法。


在專案中,對 redis 操作都已經改成全 lua 執行,因為是使用 redis 的關係,對此操作頻率肯定很高。前陣子經同事提醒,關於某些語法效能並不太好,因此對 for, pair, ipair 再次檢驗其效能。

測試條件

  • 迴圈執行次數 一百萬
  • table 長度 1000

選手一 for

1
2
3
4
5
for i=1, loopCount do
for i=1, #table_a do
x = table_a[i]
end
end

選手二 for with local variable length

1
2
3
4
5
6
for i=1, loopCount do
local leng = #table_a
for i=1, leng do
x = table_a[i]
end
end

選手三 pair

閱讀全文 »

在管理時,會需要監控哪些對 Redis 的操作比較慢(久),就有點像是 database 的 profiler 概念,會記錄所有慢的操作。

特別注意:

  • SLOWLOG 僅紀錄實際執行的時間,不包含來回請求或等待執行的時間
  • SLOWLOG 都是存在快取內,因此對效能影響很些微,可以放心在線上使用

設定 SLOWLOG 記錄門檻

SLOWLOG 有一個毫秒的門檻,超過就會被列入 SLOWLOG(default: 10ms)。要修改的話可以直接改 redis.conf 或是使用 config 指令。

執行時間超過 100ms:

1
CONFIG SET slowlog-log-slower-than 100

SLOWLOG 紀錄數量

SLOWLOG 最多需要保留幾筆(default:10筆),超過的話會先擠掉最舊的(FIFO)。

設定最多保留100筆

閱讀全文 »

結論:該使用什麼,沒有最正確,只有最適合。本篇文章選擇的方向,比較適合我在工作上遇到的情境,不見得看官也適用。

前提

冒險開始

很自然的,遇到時間,在C#階段我們會使用 DateTimeOffset,接著就很開心的存進 MongoDB。
打開MongoDB發現該欄位跟我們想得不太一樣,

alt

沒錯,DateTimeOffsetNow 變成一個陣列,裡面存的是 DateOffset,在sub document上加上 Index 絕對不是一件好事。

捨棄Offset!把它變成UTC DateTime格式吧!

哇~蒸蚌,這下欄位變成上圖的 DateTimeNow 欄位,沒有陣列了。
沒錯,這樣存進去就會變成只有一個欄位的 Date,但是這樣就夠了嗎?
經驗上這種時間格式一定都會拿來查詢條件,而查詢條件就是拿來比較的,介於~大小於這種,而這個比較的效率好嗎?肯定不會比數字來得好,就像比較字串效能還是輸給直接比較數字。

通通拿去轉Tick

閱讀全文 »

Visual studio code 已經是開發者必備的工具之一,我個人的操作上不喜歡使用內建的 Command+O 開啟功能,尤其很常在使用 terminal 時需要開啟 IDE 來編輯,所以在 terminal 使用指令 vs code 就很重要了。

設定

  1. 在 vs code 中同時按下 command + shift + p
    alt

  2. 點選 Shell Command: Install 'code' command in PATH

大功告成~

使用

只要在 terminal 輸入 code 即可開啟 vs code 囉!
但只輸入 code 只會開啟一個空白的 vs code,我通常都是會在該路徑輸入 code . 這樣會直接開啟該目錄 explorer。


這篇比較像是我自己的備忘錄,因為新環境只要設定一次,久了根本就忘記了

閱讀全文 »

事前準備

我們先將 Consul 以 docker 方式啟動

1
2
3
4
5
6
7
8
version: '3'
services:
consul-local-test.com:
image: consul:latest
container_name: consul-local-test.com
ports:
- "8500:8500"
command: ["consul", "agent", "-dev", "-client=0.0.0.0"]

接著使用瀏覽器進入Consul自帶的管理介面http://localhost:8500/

alt

點選上方 Key/Value 就可以開始編輯了
範例直接使用json格式填入

1
2
3
4
{
"Key1": 100,
"Key2": "HelloConsul"
}

這邊要特別注意的是 value 所儲存的值不可以超過 512kb

今天介紹的工具就是免費、開源的 BenchmarkDotNet
這個工具能夠協助你快速完成速度的測試,不需要再像以前一樣寫滿StopWatch、手動整理跑完的數據,最後再把計時用的程式碼還原。
透過這個工具,只需要短短幾個步驟就可以取得對照的結果。

首先需要下載、安裝這個套件。

1
Install-Package BenchmarkDotNet
閱讀全文 »