從集合的無序性看待關係型資料庫中的"序"

来源:https://www.cnblogs.com/f-ck-need-u/archive/2018/04/04/8718662.html
-Advertisement-
Play Games

本文目錄:1.集合的特征2.集合的無序性3.表中記錄的無序性4.集合的"序"和物理存儲順序之間的關係5.查詢結果(虛擬表)的無序性、隨機性6.為什麼總是強調"無序"?7.什麼時候的結果是有序的?8.索引的"序" 1.集合的特征 關係型資料庫,一方面它是資料庫,可以存儲數據,另一方面,它是關係的,也就 ...


本文目錄:
1.集合的特征
2.集合的無序性
3.表中記錄的無序性
4.集合的"序"和物理存儲順序之間的關係
5.查詢結果(虛擬表)的無序性、隨機性
6.為什麼總是強調"無序"?
7.什麼時候的結果是有序的?
8.索引的"序"

1.集合的特征

關係型資料庫,一方面它是資料庫,可以存儲數據,另一方面,它是關係的,也就是基於關係模型的。在關係型資料庫中,專門為關係模型設計了對應的"關係引擎",關係引擎中包含了語句分析器、優化器、查詢執行器。語句分析器用於分析語句是否正確,優化器用於生成查詢的執行計劃,查詢執行器按照優化器生成的執行計划去執行查詢操作,並將相關操作指令交給存儲引擎,由存儲引擎跟底層的數據(磁碟/緩存)打交道。

這裡我們不談數據存儲,而是站在資料庫的角度上談關係模型的一個特性:基於集合理論。

高中數學里,我們都學過集合有三個特征:確定性、互異性和無序性。其中確定性和互異性是成為集合的條件,無序性是集合的特性。

確定性指的是集合中的元素必須是明確的,不能在集合中存放一個可能大於2,也可能大於3這樣的元素。在關係型資料庫中,這一特征可以不用考慮,因為數據只要存到資料庫中,數據就一定是確定的。

互異性是指集合中的元素不能重覆。在關係型資料庫中,記錄是否重覆的問題沒有嚴格的規範。一方面,各種各樣的業務邏輯不允許在資料庫的角度上嚴格限制記錄的重覆性。另一方面,可以通過設置主鍵或者唯一索引來保證記錄之間不重覆,也就是"唯一性"。在很多情況下,具有唯一性的表能優化查詢,減少記錄的檢索次數。

無序性是指集合中的元素之間是無序的。在關係型資料庫中,對集合的無序性實現的最完整。甚至可以說,無序性貫穿了整個關係型資料庫,尤其是關係引擎中的優化器更是關註"序"這個概念。

因此,本文主要圍繞集合的"序",來解釋關係型資料庫中和"序"有關的行為。

2.集合的無序性

這裡的"序",不是指數據按大小排過序,也不是指物理存儲數據時排過序,而是站在集合的角度或關係引擎的角度(若不理解,就當是資料庫角度)上看"數據是否有序"的概念,它是邏輯上的"序"。

舉個例子就能理解。集合A(1,2,3,4)和集合B(2,1,4,3),看上去集合A中元素是有序的,集合B中元素是無序的。

如果要從集合A和集合B中取出小於2的元素,無論是集合A還是集合B都要比較4次才能得到最終結果,因為集合併不知道元素2的後面是否還有比2小的值。而且對於集合來說,根本就沒有前面和後面的概念。

也就是說,對於集合A來說,2是第二個元素是錯誤的說法。集合中不應該有"第"這種說法(資料庫也如此,只要檢索的對象不是order by後的結果或游標對象,取第幾行這種概念將總是按照物理存儲順序去訪問的)。

如果我們使用下圖的模式去看待這兩個集合,也用這種模式去看到資料庫表中的記錄,很多時候更有助於理解sql語法的本質和sql優化。

所以,這兩個集合是等價的集合,只不過這裡的集合A,在我們人眼中碰巧有序而已。這也是資料庫中索引的意義,我們人為地將集合中的元素排序,人為地告訴優化器它們是有序的,即使關係引擎依舊認為它是無序的。

我們可以站在集合整體的角度上看待"序"這個概念。集合不關註其內部的元素是什麼,它只關註它自身是一個容器,包含了一堆滿足集合條件的元素。當需要找出集合中某個或某些具體的元素時,需要掃描整個集合。

3.表中記錄的無序性

站在資料庫層面來講,關係型資料庫表中的數據是無序的,也就是我們俗稱的"堆heap"。我們應該這樣看待表中的每行記錄:

你可能會疑惑,使用(B+樹)索引不是可以將表中所有數據排序後存儲嗎?沒錯,但在關係引擎看來,這個表仍然是集合的,它是一個亂序的整體,其內每行數據也都認為是無序的。只不過在檢索數據的時候,優化器在生成執行計劃時能發現已經存在索引,它知道這些數據是根據索引排過序的,藉此生成成本更低的執行計劃。

轉換成上面集合的說法,索引的意義就是讓集合B(2,1,4,3)變成集合A(1,2,3,4),讓集合中的元素能夠使用"第幾"這種概念。

例如,在集合的層次上要找出值大於2的元素,需要掃描整個集合,即需要比較4次才能得到結果。同理,沒有使用索引的表也一樣會進行表掃描才能得到最終結果。當使用索引後,也就是人為地將集合B變成集合A,對於我們人來說,只要從前向後找,當找到第一個大於2的元素後(請註意,不是等於2,而是大於2,這兩種行為是有區別的),就知道它後面的所有元素一定是大於2的。對於資料庫來說,索引就是我們人為告訴優化器這個表排序過,優化器自然知道只要找到符合條件的記錄。

題外話:從這裡是否感受到了關係引擎和優化器之間的關係?

  1. 對於關係引擎來說,整個表都是無序的。如果沒有優化器組件,關係引擎(查詢執行器,後文將直接使用關係引擎來表示查詢執行器的行為)會進行表掃描,如果沒有索引,關係引擎也會進行表掃描。但是有了優化器,且經過"我們的提醒"後,優化器就能決定關係引擎的執行計劃:走索引。
  2. 另外,既然我們能隱式"提醒"優化器表存在索引,那麼我們也能顯式"提醒"優化器優化器有別的索引,甚至強制"提醒"優化器沒有索引。這就是為什麼關係型資料庫中都會有"hint"關鍵字的原因。
  3. 絕大多數情況下,我們應該完全信任優化器,相信它能幫我們選出成本最低的執行計劃。但優化器有時候也會"聰明反被聰明誤",選出一條不怎麼好甚至性能極低的執行計劃,這時我們要hint強制干涉,由我們自己告訴優化器應該怎麼走索引、走哪條索引。
  4. 從這方面看,一個不支持hint功能的資料庫系統是不合格的資料庫系統,比如老版本的PostgreSQL。當然,在2012年它已經添加了hint的擴展功能。

再來看看無序表聯接的問題。當無序表1和無序表2進行內聯接、外聯接時,我們應該這樣看待聯接的本質:

這也是站在關係引擎角度上看聯接的本質。由於無序,關係引擎只能對兩個表都進行表掃描並逐一比對,這樣就形成了我們常說的"笛卡爾積"。無疑,這樣的效率很低。為了提高聯接時的效率,應該儘可能多地減少記錄的掃描次數,這是聯接語句優化的本質。

雖然總是提到索引,感覺索引能帶來性能上的提高,但無論如何請記得,對於關係引擎來說,表是集合的,是無序的,不管它是否有索引,是否人為排序過。至於索引,它是優化器才認識的東西,關係引擎不認識。

4.集合的"序"和物理存儲順序之間的關係

先簡單說說資料庫是如何存儲數據的。

在資料庫系統中,表中的所有數據都存儲在資料庫文件中,這是磁碟上的文件。但在資料庫看來,表中的每一行數據都是存放在"頁"上的。頁是資料庫操作的最小單位,例如想讀取某一行數據時(假如走索引,不會表掃描),存儲引擎會將這行數據所在的一整頁地載入到記憶體中,並掃描這一頁。

數據頁中,使用槽位(slot)來記錄每一行數據,每個槽表示一行數據。例如,下圖是一個頁面的大致示意圖(不同資料庫系統有所不同,但不影響理解):

這個頁面中每插入一行數據,就分配一個槽位,併在槽點陣圖上標記這個槽的位置(比如距離頁面頂端的偏移位元組是多少),這樣就能知道這一行數據在頁中的位置。

而我們所說的"物理存儲順序"就是槽點陣圖標記的順序。註意,不是頁面空間上的前後位置。因為槽位的順序和頁面空間的位置可能是不一致的,例如下圖:

在頁面的空間位置上,slot2對應的記錄行在3的後面,但是掃描這個頁面的時候,將先掃描slot2,再掃描slot3。也就是說,物理順序是slot點陣圖的順序(或者說,將先返回slot2對應的行)。

在堆表中,slot點陣圖的和頁面的空間位置是完全對應的。刪除一行數據,這行數據的槽位會保留,只不過槽點陣圖上的偏移會指向0。當插入新數據的時候,這個新數據可能會直接插入到這個槽位中(如果這個槽位裝不下這行數據,則會尋找其他的槽位)。

而在有索引的情況下,slot的順序和頁面空間的位置順序可能不一樣,這關乎到索引的類型。例如插入2,它是1和3中間的值,按理說應該插在slot1對應行的後面,但這樣會使得slot3向後移動。而這樣的設計,可以讓數據直接插在頁面的尾部,只需要對slot號碼重新編號即可。性能要提高不少。

上面說的是單個頁內部的數據行順序問題。除了頁內順序,還有頁間的順序。例如頁面2緊跟在頁面1的後面,我們稱之為"頁面是連續的",但如果頁面2在頁面1的前面,或者頁面1和頁面2中間隔了很多其他的頁,我們稱之為"頁面不連續"。在頁面不連續的時候,存儲引擎需要不斷地進行頁面跳躍,反映到磁碟上就是需要不斷的定址。而我們知道,機械硬碟花在定址的時間上遠遠高於讀取數據的時間。這也稱之為"頁面碎片",當碎片較多的時候,它會對性能造成極大的影響。

本文不會去詳細介紹這些東西。在這裡,唯一需要知道的就是"數據存儲的物理順序並不是空間上的前後順序"。

那麼,集合的"序"和物理存儲順序之間有什麼關係呢?

在關係引擎看來表中的數據是無序的,但即使無序,數據也已經持久化到磁碟上了。它總要找出一個能掃描所有數據的方案。在不走索引的情況下,優化器無其他路可選,它只能按照物理存儲順序進行表掃描。在這之後,如果沒有排序演算法對數據進行排序,那麼之後所有的操作都按照這個順序訪問數據。

因此,★★★★★★物理存儲順序是無序的起點,是數據隨機性的起點。★★★★★★虛擬表之所以無序,就是從這裡物理存儲順序開始的,當表掃描(或載入部分頁面)完成後,已經載入完成的數據已經固定在記憶體中,是有固定順序的,這時候已經不適合稱之為"無序",而應該稱之為"隨機"。

5.查詢結果(虛擬表)的無序性、隨機性

除了資料庫中的實體表,在查詢的時候,中途生成的虛擬表都是無序的,但order by和distinct後的結果除外。關於order by的結果,見後文的說明。

簡單的幾個例子。

首先創建示例表,並查看表結構和數據如下:

MariaDB [test]> create table Student1 (sid int ,name char(20),age int,class char(20));
MariaDB [test]> insert into  Student1 values(3,'zhangsan',21,'Java');
                                            (6,'zhaoliu',19,'Java'),
                                            (2,'huanger',23,'Python'),
                                            (1,'chenyi',22,'Java'),
                                            (4,'lisi',20,'C#'),
                                            (5,'wangwu',21,'Python'),
                                            (7,'qianqi',22,'C'),
                                            (8,'sunba',20,'C++'),
                                            (9,'yangjiu',24,'Java');

MariaDB [test]> select * from Student1;
+------+----------+------+--------+
| sid  | name     | age  | class  |
+------+----------+------+--------+
|    3 | zhangsan |   21 | Java   |
|    6 | zhaoliu  |   19 | Java   |
|    2 | huanger  |   23 | Python |
|    1 | chenyi   |   22 | Java   |
|    4 | lisi     |   20 | C#     |
|    5 | wangwu   |   21 | Python |
|    7 | qianqi   |   22 | C      |
|    8 | sunba    |   20 | C++    |
|    9 | yangjiu  |   24 | Java   |
+------+----------+------+--------+

這裡面沒有任何索引,無論是關係引擎,還是優化器,都認為這個表是無序的,因此只能執行表掃描。而表掃描的過程是按照數據的"物理存儲順序"進行訪問的,sid=3的記錄先存進資料庫,就先訪問這個記錄(按照前文的物理存儲方式,這個說法是錯誤的,但現在忽略這個問題)。在沒有任何索引、沒有任何優化"提醒"時,優化器就會生成"按照物理存儲順序"的執行計划去表掃描。

但是表掃描的結果對於我們人類來說是無序的結果,更準確的說,是隨機的結果,是我們無法去預料的結果。因為堆中的數據在進行物理存儲時,可能會"見縫插針",而我們根本不知道這根"針"插在哪個"縫"里,也不知道它前面的數據是什麼,後面的數據是什麼。例如,堆表中的部分數據刪除了,再插入一部分數據,新插入的數據有些可能會插入在表的尾部,有些也可能插在數據刪除後留下的"槽"(slot)中。

再來說明查詢執行過程中生成的虛擬表。虛擬表是邏輯的概念,是SQL語句執行過程中每一個階段產生的數據集合,在我們人的感官上,我們會把這個集合看成虛擬表。但多數時候,它們並不真的是二維表結構的形式,只是記憶體中一段存儲了數據的緩存空間。少數時候,由於演算法或某些操作的需要,會實實在在地創建虛擬臨時表,例如使用DISTINCT子句對結果去重時,就會先生成一張臨時表用於排序並去重。

例如,在兩表聯接時我們總說會產生"笛卡爾積",然後用一張二維表的形式去感受這個笛卡爾積的虛擬表。

但在實際執行過程中不會是這樣的表結構,而應該是下麵這種結構。

也就是說,虛擬結果集中的數據是無序的,隨後對該虛擬結果集的操作也是隨機而無法保證順序的。例如上面的笛卡爾積結果集,如果使用了WHERE子句篩選某些行,則篩選的過程是對笛卡爾積進行"表"掃描,但笛卡爾積本就是不保證順序的,所以當where篩選出多行時,這些行的順序可能會和我們預料的結果有所不同。當然,優化器不會真的採用這樣的方案,但站在邏輯角度上看,因為虛擬結果集無序,要從中檢索數據只能進行"表"掃描。

再比如說TOP子句(MySQL、MariaDB中等價的是LIMIT子句),如果沒有結合ORDER BY子句,那麼TOP將從其前面的虛擬結果集中按某種順序挑出滿足數量的行出來,挑出的這些行是我們人無法預料的,所以TOP的結果是隨機的。這裡的"某種順序"並非有序,例如從上圖的笛卡爾積中選一行時,由於笛卡爾積是無序的,挑選的這一行將受表A的物理存儲順序、表B的物理存儲順序影響。

只有使用了ORDER BY子句,才能保證TOP的結果是可預料而非隨機的,因為ORDER BY的虛擬結果集是有序的。事實上,ORDER BY的結果不應該叫"集",而應該叫"游標對象",因為排序後的結果中,每一行都按照我們期待的順序固定好了位置,之後TOP再去操作這樣的結果就一定能得到我們預料之中的數據。

6.為什麼總是強調"無序"

通過前面的內容,我們已經發現無序性的最大問題在於返回結果的無法預測性。返回結果無法預測,意味著數據增、刪、改的時候存在危險,意味著我們可能對檢索的數據認知不足。

7.什麼時候的數據是有序的?

前面說了一大堆,總結一下就是:數據都是無序的,每一步的檢索都有隨機性,無法保證能達到我們人的期待。但是,關係型資料庫中的所有數據都是無序,都是隨機的嗎?換句話說,上面的總結對嗎?答案是不對。

在關係型資料庫中,我們除了考慮從存儲引擎到磁碟這段路程(受物理存儲順序影響),還要考慮語句執行過程中記憶體中的虛擬表。在前面,我們說虛擬表是無序的,這句話不准確。

一方面,數據載入成功後,它們在記憶體中已經是有序的,但對我們人來說,我們無法看到這樣的"序",也就是說結果是隨機的,是我們無法預料的。

另一方面,當有排序演算法對虛擬表進行排序後,結果也是有序的,這樣的結果是符合我們人所預料的。對於排序後的結果,ANSI將其稱之為"游標對象"。

常見的兩個涉及到排序演算法的子句是ORDER BY和DISTINCT。此處之外,還有游標自身,它的結果也是有序的。

對於ORDER BY子句,它會將它前面的虛擬結果集進行排序,排序的結果集中,每行記錄都固定好了位置,我們可以預料到任何一行數據處於哪個位置,也知道它前面是什麼數據,後面是什麼數據。也就是說,排序後的數據是固定而非隨機的。

對於DISTINCT子句,在對其前面的虛擬結果集進行去重操作時,DISTINCT總會帶有排序操作(即使沒有指定order by,內部也自帶排序),排序之後再對結果集進行去重。例如下麵的表。

 id   name
----  -----
 5     e
 2     b
 4     d
 1     a
 2     x
 3     c

對id列去重時,它將對id列進行排序,得到的結果將是:

 id
----
 1
 2
 3
 4
 5

結果是有序的。但對於id=2的記錄來說,在去重時應該保留name=b的還是name=x的記錄呢?無法保證,因為DISTINCT只對id列排序,不對id之外的列排序。因此對於有重覆值的記錄,DISTINCT只能返回一個隨機記錄,我們無法預料這個記錄是不是我們想要的結果。

在SQL Server和Oracle中這沒什麼問題,因為使用DISTINCT後,它後面的過程不允許使用非DISTINCT列(DISTINCT後面還有ORDER BY和TOP,但涉及到列的只有ORDER BY子句),因此最終得到的結果只有指定的去重列(id列)。但是在MySQL/MariaDB中,ORDER BY允許使用非DISTINCT列,例如select distinct id from t1 order by name,它將先按name排序,再按id排序,最後對id去重。也許你發現了,這種情況下DISTINCT是在ORDER BY之後才執行的,沒錯,事實就是如此。

8.索引的"序"

無論是MySQL還是SQL Server(Oracle的知識都忘光了,所以不說它了),都可以創建"聚集索引"和"非聚集索引"(MySQL中沒有這種稱呼,但它的主鍵索引就是聚集索引,非主鍵索引就是非聚集索引,非聚集索引有時候也稱之為secondary index)。它們都是B+樹的組織結構。

對於聚集索引,B+樹的葉級頁包含了所有數據行以及所有列(有些時候還包括一個或兩個額外的列),它們是排過序的。但是這種排序是通過雙鏈表和指針的方式實現的。

例如,表中有數據行1,2,3,4,5,6,假設這幾行數據都較大,每兩行占用一個數據頁面,那麼存儲數據的數據頁總共需要3頁(假設分別稱為A、B、C頁)。

這3頁之間通過雙鏈表的方式組織起來,例如B頁的page header中記錄了它前一頁是A,後一頁是C,C頁的page header中記錄了它的前一頁是B,沒有後一頁(用0表示)。

而對於頁面內的數據,則是通過slot槽位偏移指針來組織的。在前面的"物理存儲順序"一節中已經說明瞭這個葉級頁是如何每行數據的。

無論是聚集索引還是非聚集索引,都必須要有一列或多列能唯一識別每一行記錄。可以通過同時創建唯一性索引的方式實現,在沒有創建唯一性索引時,系統內部會自動添加一個列,幫助索引列唯一識別每一行記錄,只不過當沒有重覆值的時候,這一列占用的空間未0。

總之,有了索引,無論是聚集還是非聚集索引,都一定能保證每一行數據都唯一,每一行數據在排序時都有完全確定的位置。也就是說,當我們走索引去檢索數據的時候,數據不再無序,返回的結果也總能預料到。

 

回到Linux系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
回到網站架構系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
回到資料庫系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7586194.html
轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/8718662.html

註:若您覺得這篇文章還不錯請點擊右下角推薦,您的支持能激發作者更大的寫作熱情,非常感謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是 ARM Cortex M學習資源 。 概念科普類 資源 版本 短評 Cortex M ARM官方主頁 / 最權威的Cortex M資源來源,最新的Cortex M技術應該從這裡去找 ARM_Cortex M維基百科 / 對於技術名詞的 ...
  • Linux管理磁碟 查看當前磁碟使用情況: (查看所有的硬碟) 伺服器添加硬碟:在系統設置添加 分區: (sdb, sdc, sde) 指令: (幫助信息), (新加分區) 第二步: 指令 第三步:寫入磁碟 使用:掛載: 掛載到/data目錄下,掛載成功如下 可以掛載到多個設備 Vi命令 所有的指令 ...
  • 1.NFC基本概念: NFC 又稱為近場通信,是一種新興技術,可以在彼此靠近的情況下進行數據交換,是由非接觸式射頻識別(RFID)及互連互通技術整合演變而來,通過單一晶元集成感應式讀卡器; NFC有效通訊距離一般不超過10釐米,其傳輸速度有106 Kbit/秒、212 Kbit/秒或者424 Kbi ...
  • 大佬先別吐槽,既然我們說好了要手把手教學,那我們就從進入DWVA開始吧, (才不是因為我是小白只會這個的說。。) 那麼如何進入DVWA呢?九頭蛇Hydra? 大佬留步!!別衝動,這點小事我們的burpsuite代勞就夠了。。。 這裡我們可以看到,我們的賬號密碼通過該post包提交。 預設為我們面對一 ...
  • 不廢話,直奔主題,可以覆蓋安裝。 下載並安裝MySQL官方的 Yum Repository 使用上面的命令就直接下載了安裝用的Yum Repository,大概25KB的樣子,然後就可以直接yum安裝了。 之後就開始安裝MySQL伺服器。 這步可能會花些時間,安裝完成後就會覆蓋掉之前的mariadb ...
  • 本文為mariadb官方手冊:DECLARE HANDLER的譯文。 原文:https://mariadb.com/kb/en/library/declare-handler/我提交到MariaDB官方手冊的譯文:https://mariadb.com/kb/zh-cn/declare-handle ...
  • GT(隨身調)是APP的隨身調測平臺,它是直接運行在手機上的“集成調測環境”(IDTE, Integrated Debug Environment)。利用GT,僅憑一部手機,無需連接電腦,您即可對APP進行快速的性能測試(CPU、記憶體、流量、電量、幀率/流暢度等等)、開發日誌的查看、Crash日誌查 ...
  • 1、下載mysql 下載的話先確認好版本。 system:centos7 mysql:5.7 下麵的版本自己選擇,一般是86位的。 下載好的文件 2、上傳到伺服器 soft文件夾,終端也進入了soft文件夾 第一種是用xshell上傳 $ rz 需要安裝 yum install lrzsz -y 第 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...