該如何選擇ClickHouse的表引擎

来源:https://www.cnblogs.com/luolei0120/archive/2023/07/20/17568670.html
-Advertisement-
Play Games

該如何選擇ClickHouse的表引擎 本文將介紹ClickHouse中一個非常重要的概念—表引擎(table engine)。如果對MySQL熟悉的話,或許你應該聽說過InnoDB和MyISAM存儲引擎。不同的存儲引擎提供不同的存儲機制、索引方式、鎖定水平等功能,也可以稱之為表類型。ClickHo ...


該如何選擇ClickHouse的表引擎

 

本文將介紹ClickHouse中一個非常重要的概念—表引擎(table engine)。如果對MySQL熟悉的話,或許你應該聽說過InnoDB和MyISAM存儲引擎。不同的存儲引擎提供不同的存儲機制、索引方式、鎖定水平等功能,也可以稱之為表類型。ClickHouse提供了豐富的表引擎,這些不同的表引擎也代表著不同的表類型。比如數據表擁有何種特性、數據以何種形式被存儲以及如何被載入。本文會對ClickHouse中常見的表引擎進行介紹,主要包括以下內容:

表引擎的作用是什麼

MergeTree系列引擎

Log家族系列引擎

外部集成表引擎

其他特殊的表引擎

溫馨提示:本文內容較長,建議收藏

表引擎的作用是什麼
決定表存儲在哪裡以及以何種方式存儲

支持哪些查詢以及如何支持

併發數據訪問

索引的使用

是否可以執行多線程請求

數據複製參數

表引擎分類
引擎分類 引擎名稱
MergeTree系列 MergeTree 、ReplacingMergeTree 、SummingMergeTree 、 AggregatingMergeTree CollapsingMergeTree 、 VersionedCollapsingMergeTree 、GraphiteMergeTree
Log系列 TinyLog 、StripeLog 、Log
Integration Engines Kafka 、MySQL、ODBC 、JDBC、HDFS
Special Engines Distributed 、MaterializedView、 Dictionary 、Merge 、File、Null 、Set 、Join 、 URL View、Memory 、 Buffer
Log系列表引擎
應用場景
Log系列表引擎功能相對簡單,主要用於快速寫入小表(1百萬行左右的表),然後全部讀出的場景。即一次寫入多次查詢。

Log系列表引擎的特點
共性特點

數據存儲在磁碟上

當寫數據時,將數據追加到文件的末尾

不支持併發讀寫,當向表中寫入數據時,針對這張表的查詢會被阻塞,直至寫入動作結束

不支持索引

不支持原子寫:如果某些操作(異常的伺服器關閉)中斷了寫操作,則可能會獲得帶有損壞數據的表

不支持ALTER操作(這些操作會修改表設置或數據,比如delete、update等等)

區別

TinyLog

TinyLog是Log系列引擎中功能簡單、性能較低的引擎。它的存儲結構由數據文件和元數據兩部分組成。其中,數據文件是按列獨立存儲的,也就是說每一個列欄位都對應一個文件。除此之外,TinyLog不支持併發數據讀取。

StripLog支持併發讀取數據文件,當讀取數據時,ClickHouse會使用多線程進行讀取,每個線程處理一個單獨的數據塊。另外,StripLog將所有列數據存儲在同一個文件中,減少了文件的使用數量。

Log支持併發讀取數據文件,當讀取數據時,ClickHouse會使用多線程進行讀取,每個線程處理一個單獨的數據塊。Log引擎會將每個列數據單獨存儲在一個獨立文件中。

TinyLog表引擎使用
該引擎適用於一次寫入,多次讀取的場景。對於處理小批數據的中間表可以使用該引擎。值得註意的是,使用大量的小表存儲數據,性能會很低。

CREATE TABLE emp_tinylog (
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資'
)ENGINE=TinyLog();

INSERT INTO emp_tinylog
VALUES (1,'tom','上海',25,'技術部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_tinylog
VALUES (3,'bob','北京',33,'財務部',50000),(4,'tony','杭州',28,'銷售事部',50000);
進入預設數據存儲目錄,查看底層數據存儲形式,可以看出:TinyLog引擎表每一列都對應的文件

[root@cdh04 emp_tinylog]# pwd
/var/lib/clickhouse/data/default/emp_tinylog
[root@cdh04 emp_tinylog]# ll
總用量 28
-rw-r----- 1 clickhouse clickhouse 56 9月 17 14:33 age.bin
-rw-r----- 1 clickhouse clickhouse 97 9月 17 14:33 depart.bin
-rw-r----- 1 clickhouse clickhouse 60 9月 17 14:33 emp_id.bin
-rw-r----- 1 clickhouse clickhouse 70 9月 17 14:33 name.bin
-rw-r----- 1 clickhouse clickhouse 68 9月 17 14:33 salary.bin
-rw-r----- 1 clickhouse clickhouse 185 9月 17 14:33 sizes.json
-rw-r----- 1 clickhouse clickhouse 80 9月 17 14:33 work_place.bin
## 查看sizes.json數據
## 在sizes.json文件內使用JSON格式記錄了每個.bin文件內對應的數據大小的信息
{
"yandex":{
"age%2Ebin":{
"size":"56"
},
"depart%2Ebin":{
"size":"97"
},
"emp_id%2Ebin":{
"size":"60"
},
"name%2Ebin":{
"size":"70"
},
"salary%2Ebin":{
"size":"68"
},
"work_place%2Ebin":{
"size":"80"
}
}
}

當我們執行ALTER操作時會報錯,說明該表引擎不支持ALTER操作

-- 以下操作會報錯:
-- DB::Exception: Mutations are not supported by storage TinyLog.
ALTER TABLE emp_tinylog DELETE WHERE emp_id = 5;
ALTER TABLE emp_tinylog UPDATE age = 30 WHERE emp_id = 4;
StripLog表引擎使用
相比TinyLog而言,StripeLog擁有更高的查詢性能(擁有.mrk標記文件,支持並行查詢),同時其使用了更少的文件描述符(所有數據使用同一個文件保存)。

CREATE TABLE emp_stripelog (
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資'
)ENGINE=StripeLog;
-- 插入數據
INSERT INTO emp_stripelog
VALUES (1,'tom','上海',25,'技術部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_stripelog
VALUES (3,'bob','北京',33,'財務部',50000),(4,'tony','杭州',28,'銷售事部',50000);
-- 查詢數據
-- 由於是分兩次插入數據,所以查詢時會有兩個數據塊
cdh04 :) select * from emp_stripelog;

SELECT *
FROM emp_stripelog

┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │
│ 2 │ jack │ 上海 │ 26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 3 │ bob │ 北京 │ 33 │ 財務部 │ 50000.00 │
│ 4 │ tony │ 杭州 │ 28 │ 銷售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘

進入預設數據存儲目錄,查看底層數據存儲形式

[root@cdh04 emp_stripelog]# pwd
/var/lib/clickhouse/data/default/emp_stripelog
[root@cdh04 emp_stripelog]# ll
總用量 12
-rw-r----- 1 clickhouse clickhouse 673 9月 17 15:11 data.bin
-rw-r----- 1 clickhouse clickhouse 281 9月 17 15:11 index.mrk
-rw-r----- 1 clickhouse clickhouse 69 9月 17 15:11 sizes.json

可以看出StripeLog表引擎對應的存儲結構包括三個文件:

data.bin:數據文件,所有的列欄位使用同一個文件保存,它們的數據都會被寫入data.bin。

index.mrk:數據標記,保存了數據在data.bin文件中的位置信息(每個插入數據塊對應列的offset),利用數據標記能夠使用多個線程,以並行的方式讀取data.bin內的壓縮數據塊,從而提升數據查詢的性能。

sizes.json:元數據文件,記錄了data.bin和index.mrk大小的信息

提示:

StripeLog引擎將所有數據都存儲在了一個文件中,對於每次的INSERT操作,ClickHouse會將數據塊追加到表文件的末尾

StripeLog引擎同樣不支持ALTER UPDATE 和ALTER DELETE 操作

Log表引擎使用
Log引擎表適用於臨時數據,一次性寫入、測試場景。Log引擎結合了TinyLog表引擎和StripeLog表引擎的長處,是Log系列引擎中性能最高的表引擎。

CREATE TABLE emp_log (
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資'
)ENGINE=Log;

INSERT INTO emp_log VALUES (1,'tom','上海',25,'技術部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_log VALUES (3,'bob','北京',33,'財務部',50000),(4,'tony','杭州',28,'銷售事部',50000);
-- 查詢數據,
-- 由於是分兩次插入數據,所以查詢時會有兩個數據塊
cdh04 :) select * from emp_log;

SELECT *
FROM emp_log

┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │
│ 2 │ jack │ 上海 │ 26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 3 │ bob │ 北京 │ 33 │ 財務部 │ 50000.00 │
│ 4 │ tony │ 杭州 │ 28 │ 銷售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘
進入預設數據存儲目錄,查看底層數據存儲形式

[root@cdh04 emp_log]# pwd
/var/lib/clickhouse/data/default/emp_log
[root@cdh04 emp_log]# ll
總用量 32
-rw-r----- 1 clickhouse clickhouse 56 9月 17 15:55 age.bin
-rw-r----- 1 clickhouse clickhouse 97 9月 17 15:55 depart.bin
-rw-r----- 1 clickhouse clickhouse 60 9月 17 15:55 emp_id.bin
-rw-r----- 1 clickhouse clickhouse 192 9月 17 15:55 __marks.mrk
-rw-r----- 1 clickhouse clickhouse 70 9月 17 15:55 name.bin
-rw-r----- 1 clickhouse clickhouse 68 9月 17 15:55 salary.bin
-rw-r----- 1 clickhouse clickhouse 216 9月 17 15:55 sizes.json
-rw-r----- 1 clickhouse clickhouse 80 9月 17 15:55 work_place.bin

Log引擎的存儲結構包含三部分:

列.bin:數據文件,數據文件按列單獨存儲

__marks.mrk:數據標記,統一保存了數據在各個.bin文件中的位置信息。利用數據標記能夠使用多個線程,以並行的方式讀取。.bin內的壓縮數據塊,從而提升數據查詢的性能。

sizes.json:記錄了.bin和__marks.mrk大小的信息

提示:

Log表引擎會將每一列都存在一個文件中,對於每一次的INSERT操作,都會對應一個數據塊

MergeTree系列引擎
在所有的表引擎中,最為核心的當屬MergeTree系列表引擎,這些表引擎擁有最為強大的性能和最廣泛的使用場合。對於非MergeTree系列的其他引擎而言,主要用於特殊用途,場景相對有限。而MergeTree系列表引擎是官方主推的存儲引擎,支持幾乎所有ClickHouse核心功能。

MergeTree表引擎
MergeTree在寫入一批數據時,數據總會以數據片段的形式寫入磁碟,且數據片段不可修改。為了避免片段過多,ClickHouse會通過後臺線程,定期合併這些數據片段,屬於相同分區的數據片段會被合成一個新的片段。這種數據片段往複合併的特點,也正是合併樹名稱的由來。

MergeTree作為家族系列最基礎的表引擎,主要有以下特點:

存儲的數據按照主鍵排序:允許創建稀疏索引,從而加快數據查詢速度

支持分區,可以通過PRIMARY KEY語句指定分區欄位。

支持數據副本

支持數據採樣

建表語法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
...
INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]
ENGINE:ENGINE = MergeTree(),MergeTree引擎沒有參數

ORDER BY:排序欄位。比如ORDER BY (Col1, Col2),值得註意的是,如果沒有指定主鍵,預設情況下 sorting key(排序欄位)即為主鍵。如果不需要排序,則可以使用**ORDER BY tuple()**語法,這樣的話,創建的表也就不包含主鍵。這種情況下,ClickHouse會按照插入的順序存儲數據。必選。

PARTITION BY:分區欄位,可選。

PRIMARY KEY:指定主鍵,如果排序欄位與主鍵不一致,可以單獨指定主鍵欄位。否則預設主鍵是排序欄位。可選。

SAMPLE BY:採樣欄位,如果指定了該欄位,那麼主鍵中也必須包含該欄位。比如SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))。可選。

TTL:數據的存活時間。在MergeTree中,可以為某個列欄位或整張表設置TTL。當時間到達時,如果是列欄位級別的TTL,則會刪除這一列的數據;如果是表級別的TTL,則會刪除整張表的數據。可選。

SETTINGS:額外的參數配置。可選。

建表示例

CREATE TABLE emp_mergetree (
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資'
)ENGINE=MergeTree()
ORDER BY emp_id
PARTITION BY work_place
;
-- 插入數據
INSERT INTO emp_mergetree
VALUES (1,'tom','上海',25,'技術部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_mergetree
VALUES (3,'bob','北京',33,'財務部',50000),(4,'tony','杭州',28,'銷售事部',50000);

-- 查詢數據
-- 按work_place進行分區
cdh04 :) select * from emp_mergetree;

SELECT *
FROM emp_mergetree

┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 3 │ bob │ 北京 │ 33 │ 財務部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │
│ 2 │ jack │ 上海 │ 26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 4 │ tony │ 杭州 │ 28 │ 銷售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘
查看一下數據存儲格式,可以看出,存在三個分區文件夾,每一個分區文件夾記憶體儲了對應分區的數據。

[root@cdh04 emp_mergetree]# pwd
/var/lib/clickhouse/data/default/emp_mergetree
[root@cdh04 emp_mergetree]# ll
總用量 16
drwxr-x--- 2 clickhouse clickhouse 4096 9月 17 17:45 1c89a3ba9fe5fd53379716a776c5ac34_3_3_0
drwxr-x--- 2 clickhouse clickhouse 4096 9月 17 17:44 40d45822dbd7fa81583d715338929da9_1_1_0
drwxr-x--- 2 clickhouse clickhouse 4096 9月 17 17:45 a6155dcc1997eda1a348cd98b17a93e9_2_2_0
drwxr-x--- 2 clickhouse clickhouse 6 9月 17 17:43 detached
-rw-r----- 1 clickhouse clickhouse 1 9月 17 17:43 format_version.txt
進入一個分區目錄查看

 

checksums.txt:校驗文件,使用二進位格式存儲。它保存了餘下各類文件(primary. idx、count.txt等)的size大小及size的哈希值,用於快速校驗文件的完整性和正確性。

columns.txt:列信息文件,使用明文格式存儲。用於保存此數據分區下的列欄位信息,例如

[root@cdh04 1c89a3ba9fe5fd53379716a776c5ac34_3_3_0]# cat columns.txt
columns format version: 1
6 columns:
`emp_id` UInt16
`name` String
`work_place` String
`age` UInt8
`depart` String
`salary` Decimal(9, 2)
count.txt:計數文件,使用明文格式存儲。用於記錄當前數據分區目錄下數據的總行數

primary.idx:一級索引文件,使用二進位格式存儲。用於存放稀疏索引,一張MergeTree表只能聲明一次一級索引,即通過ORDER BY或者PRIMARY KEY指定欄位。藉助稀疏索引,在數據查詢的時能夠排除主鍵條件範圍之外的數據文件,從而有效減少數據掃描範圍,加速查詢速度。

列.bin:數據文件,使用壓縮格式存儲,預設為LZ4壓縮格式,用於存儲某一列的數據。由於MergeTree採用列式存儲,所以每一個列欄位都擁有獨立的.bin數據文件,並以列欄位名稱命名。

列.mrk2:列欄位標記文件,使用二進位格式存儲。標記文件中保存了.bin文件中數據的偏移量信息

partition.dat與minmax_[Column].idx:如果指定了分區鍵,則會額外生成partition.dat與minmax索引文件,它們均使用二進位格式存儲。partition.dat用於保存當前分區下分區表達式最終生成的值,即分區欄位值;而minmax索引用於記錄當前分區下分區欄位對應原始數據的最小和最大值。比如當使用EventTime欄位對應的原始數據為2020-09-17、2020-09-30,分區表達式為PARTITION BY toYYYYMM(EventTime),即按月分區。partition.dat中保存的值將會是2019-09,而minmax索引中保存的值將會是2020-09-17 2020-09-30。

註意點

多次插入數據,會生成多個分區文件

-- 新插入兩條數據
cdh04 :) INSERT INTO emp_mergetree
VALUES (5,'robin','北京',35,'財務部',50000),(6,'lilei','北京',38,'銷售事部',50000);

-- 查詢結果
cdh04 :) select * from emp_mergetree;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 3 │ bob │ 北京 │ 33 │ 財務部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name──┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 5 │ robin │ 北京 │ 35 │ 財務部 │ 50000.00 │
│ 6 │ lilei │ 北京 │ 38 │ 銷售事部 │ 50000.00 │
└────────┴───────┴────────────┴─────┴──────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │
│ 2 │ jack │ 上海 │ 26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 4 │ tony │ 杭州 │ 28 │ 銷售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘

可以看出,新插入的數據新生成了一個數據塊,並沒有與原來的分區數據在一起,我們可以執行optimize命令,執行合併操作

-- 執行合併操作
cdh04 :) OPTIMIZE TABLE emp_mergetree PARTITION '北京';
-- 再次執行查詢
cdh04 :) select * from emp_mergetree;
SELECT *
FROM emp_mergetree

┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │
│ 2 │ jack │ 上海 │ 26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name──┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 3 │ bob │ 北京 │ 33 │ 財務部 │ 50000.00 │
│ 5 │ robin │ 北京 │ 35 │ 財務部 │ 50000.00 │
│ 6 │ lilei │ 北京 │ 38 │ 銷售事部 │ 50000.00 │
└────────┴───────┴────────────┴─────┴──────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│ 4 │ tony │ 杭州 │ 28 │ 銷售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘

執行上面的合併操作之後,會新生成一個該分區的文件夾,原理的分區文件夾不變。

在MergeTree中主鍵並不用於去重,而是用於索引,加快查詢速度

-- 插入一條相同主鍵的數據
INSERT INTO emp_mergetree
VALUES (1,'sam','杭州',35,'財務部',50000);
-- 會發現該條數據可以插入,由此可知,並不會對主鍵進行去重
ReplacingMergeTree表引擎
上文提到MergeTree表引擎無法對相同主鍵的數據進行去重,ClickHouse提供了ReplacingMergeTree引擎,可以針對相同主鍵的數據進行去重,它能夠在合併分區時刪除重覆的數據。值得註意的是,ReplacingMergeTree只是在一定程度上解決了數據重覆問題,但是並不能完全保障數據不重覆。

建表語法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = ReplacingMergeTree([ver])
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在使用DevExpress的GridView的時候,我們為了方便,往往使用一些擴展函數,動態創建GridView列的編輯控制項對象,然後我們可以靈活的對內容進行編輯或者使用一些彈出的對話框窗體進行處理內容的錄入,本篇隨筆就是介紹這一主題:在DevExpress的GridView的列中,動態創建列的時候... ...
  • ## 簡介 ##### IoC Ioc控制反轉,是一種設計模式和原則,旨在解耦組件之間的依賴關係,並將對象的創建和管理委托外部容器。是面向編程中一種重要的概念,用於提高代碼的可維護性. 核心思想:通過將控制權從高層轉移到底層模塊,實現對依賴關係的控制反轉,傳統上,一個對象通常負責自己的依賴項創建和管 ...
  • 本文介紹了值類型和引用類型在編程中的區別。值類型包括簡單類型、枚舉類型和結構體類型,通常被分配線上程的堆棧上,變數保存的是實例數據本身。引用類型實例則被分配在托管堆上,變數保存的是實例數據的記憶體地址。值類型由操作系統負責管理,而引用類型則由垃圾回收機制(GC)負責管理。本文還通過示例代碼展示了值類型... ...
  • ## 一:背景 ### 1. 講故事 這篇文章源自於分析一些疑難dump的思考而產生的靈感,在dump分析中經常要尋找的一個答案就是如何找到死亡線程的生前都做了一些什麼?參考如下輸出: ``` C# 0:001> !t ThreadCount: 22 UnstartedThread: 0 Backg ...
  • 本文介紹了 C# 中委托的定義、使用、為什麼引入委托以及委托的本質。同時,還介紹了委托鏈的使用,即將多個委托鏈接在一起,提高程式的可擴展性。 ...
  • > 2023/7/20 初學內核,記錄與分享,感嘆內核學了後真的感覺很多東西都通透了,但是難度太大,只能淺淺初探。 # 前提 內核五大功能 ➢ **進程管理**:進程的創建,銷毀,調度等功能 註:可中斷,不可中斷,就是是否被信號打斷。從運行狀態怎樣改到可中斷等待態,和不可中斷等待態操作系統開始會對每 ...
  • ARP學習和老化機制在Linux網路通信中起著至關重要的作用。ARP(Address Resolution Protocol)地址解析協議是將IP地址解析為MAC地址的一種機制。本文將詳細介紹Linux中ARP學習和老化的概念、工作原理以及其重要性。 ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202307/3076680-20230719150159605-2139117895.png) # 1. 變換結果集成一行 ## 1.1. 結果集 ```sql DEPTNO CNT 10 3 20 5 30 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...