MySQL 執行計劃詳解

来源:https://www.cnblogs.com/Jcloud/archive/2023/08/15/17630571.html
-Advertisement-
Play Games

本文從EXPLAIN分析SQL的執行計劃開始,進行示例展示,並對輸出結果進行解讀,同時總結了EXPLAIN可產生額外的擴展信息以及EXPLAIN的估計查詢性能,整篇文章基於MySQL 8.0編寫,理論支持MySQL 5.0及更高版本。 ...


1. EXPLAIN詳解

本文基於MySQL 8.0編寫,理論支持MySQL 5.0及更高版本。

2. EXPLAIN使用

2.1 explain分析SQL的執行計劃

{EXPLAIN | DESCRIBE | DESC}
  tbl_name [col_name | wild]

{EXPLAIN | DESCRIBE | DESC}
    [explain_type]
    {explainable_stmt | FOR CONNECTION connection_id}

{EXPLAIN | DESCRIBE | DESC} ANALYZE select_statement    

explain_type: {
    FORMAT = format_name
}

format_name: {
    TRADITIONAL
  | JSON
  | TREE
}

explainable_stmt: {
    SELECT statement
  | TABLE statement
  | DELETE statement
  | INSERT statement
  | REPLACE statement
  | UPDATE statement
}

2.2 示例

EXPLAIN format = TRADITIONAL json SELECT tt.TicketNumber, tt.TimeIn,
        tt.ProjectReference, tt.EstimatedShipDate,
        tt.ActualShipDate, tt.ClientID,
        tt.ServiceCodes, tt.RepetitiveID,
        tt.CurrentProcess, tt.CurrentDPPerson,
        tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
        et_1.COUNTRY, do.CUSTNAME
FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL
  AND tt.ActualPC = et.EMPLOYID
  AND tt.AssignedPC = et_1.EMPLOYID
  AND tt.ClientID = do.CUSTNMBR;

2.3 結果輸出展示

3. 結果解讀

  • id:該語句的唯一標識。如果explain的結果包括多個id值,則數字越大越先執行;而對於相同id的行,則表示從上往下依次執行。
  • select_type:查詢類型,有如下幾種取值:

  • table:表示當前這一行正在訪問哪張表,如果SQL定義了別名,則展示表的別名
  • partitions:當前查詢匹配記錄的分區。對於未分區的表,返回null
  • type:連接類型,有如下幾種取值,性能從好到壞排序如下:

system:該表只有一行(相當於系統表),system是const類型的特例

const:針對主鍵或唯一索引的等值查詢掃描, 最多只返回一行數據. const 查詢速度非常快, 因為它僅僅讀取一次即可

eq_ref:當使用了索引的全部組成部分,並且索引是PRIMARY KEY或UNIQUE NOT NULL 才會使用該類型,性能僅次於system及const。

-- 多表關聯查詢,單行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

-- 多表關聯查詢,聯合索引,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

ref:當滿足索引的最左首碼規則,或者索引不是主鍵也不是唯一索引時才會發生。如果使用的索引只會匹配到少量的行,性能也是不錯的。

-- 根據索引(非主鍵,非唯一索引),匹配到多行
SELECT * FROM ref_table WHERE key_column=expr;

-- 多表關聯查詢,單個索引,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

-- 多表關聯查詢,聯合索引,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

TIPS最左首碼原則

指的是索引按照最左優先的方式匹配索引。比如創建了一個組合索引(column1, column2, column3),那麼,如果查詢條件是: WHERE column1 = 1、WHERE column1= 1 AND column2 = 2、WHERE column1= 1 AND column2 = 2 AND column3 = 3 都可以使用該索引; WHERE column1 = 2、WHERE column1 = 1 AND column3 = 3就無法匹配該索引。

fulltext:全文索引ref_or_null:該類型類似於ref,但是MySQL會額外搜索哪些行包含了NULL。這種類型常見於解析子查詢

SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;

index_merge:此類型表示使用了索引合併優化,表示一個查詢裡面用到了多個索引

unique_subquery:該類型和eq_ref類似,但是使用了IN查詢,且子查詢是主鍵或者唯一索引。例如:value IN (SELECT primary_key FROM single_table WHERE some_expr)

index_subquery:和unique_subquery類似,只是子查詢使用的是非唯一索引。value IN (SELECT key_column FROM single_table WHERE some_expr)

range:範圍掃描,表示檢索了指定範圍的行,主要用於有限制的索引掃描。比較常見的範圍掃描是帶有BETWEEN子句或WHERE子句里有>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE、IN()等操作符。

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);

index:全索引掃描,和ALL類似,只不過index是全盤掃描了索引的數據。當查詢僅使用索引中的一部分列時,可使用此類型。有兩種場景會觸發:

▪如果索引是查詢的覆蓋索引,並且索引查詢的數據就可以滿足查詢中所需的所有數據,則只掃描索引樹。此時,explain的Extra 列的結果是Using index。index通常比ALL快,因為索引的大小通常小於表數據。

▪按索引的順序來查找數據行,執行了全表掃描。此時,explain的Extra列的結果不會出現Uses index。

ALL:全表掃描,性能最差。

  • possible_keys:展示當前查詢可以使用哪些索引,這一列的數據是在優化過程的早期創建的,因此有些索引可能對於後續優化過程是沒用的。
  • key:表示MySQL實際選擇的索引key_len:索引使用的位元組數。由於存儲格式,當欄位允許為NULL時,key_len比不允許為空時大1位元組。

◦key_len計算公式:https://www.cnblogs.com/gomysql/p/4004244.html

  • ref:表示將哪個欄位或常量和key列所使用的欄位進行比較。如果ref是一個函數,則使用的值是函數的結果。要想查看是哪個函數,可在EXPLAIN語句之後緊跟一個SHOW WARNING語句。
  • rows:MySQL估算會掃描的行數,數值越小越好。
  • filtered:表示符合查詢條件的數據百分比,最大100。用rows × filtered可獲得和下一張表連接的行數。例如rows = 1000,filtered = 50%,則和下一張表連接的行數是500。

TIPS

在MySQL 5.7之前,想要顯示此欄位需使用explain extended命令; MySQL.5.7及更高版本,explain預設就會展示filtered

  • Extra:展示有關本次查詢的附加信息,取值如下:

◦Child of ‘table’ pushed join@1:此值只會在NDB Cluster下出現。

◦const row not found:例如查詢語句SELECT … FROM tbl_name,而表是空的

◦Deleting all rows:對於DELETE語句,某些引擎(例如MyISAM)支持以一種簡單而快速的方式刪除所有的數據,如果使用了這種優化,則顯示此值

◦Distinct:查找distinct值,當找到第一個匹配的行後,將停止為當前行組合搜索更多行

◦FirstMatch(tbl_name):當前使用了半連接FirstMatch策略,詳見 https://mariadb.com/kb/en/firstmatch-strategy/ ,翻譯 https://www.cnblogs.com/abclife/p/10895624.html

◦Full scan on NULL key:子查詢中的一種優化方式,在無法通過索引訪問null值的時候使用

◦Impossible HAVING:HAVING子句始終為false,不會命中任何行

◦Impossible WHERE:WHERE子句始終為false,不會命中任何行

◦Impossible WHERE noticed after reading const tables:MySQL已經讀取了所有const(或system)表,併發現WHERE子句始終為false

◦LooseScan(m…n):當前使用了半連接LooseScan策略,詳見 https://mariadb.com/kb/en/loosescan-strategy/ ,翻譯 http://www.javacoder.cn/?p=39

◦No matching min/max row:沒有任何能滿足例如 SELECT MIN(…) FROM … WHERE condition 中的condition的行

◦no matching row in const table:對於關聯查詢,存在一個空表,或者沒有行能夠滿足唯一索引條件

◦No matching rows after partition pruning:對於DELETE或UPDATE語句,優化器在partition pruning(分區修剪)之後,找不到要delete或update的內容

◦No tables used:當此查詢沒有FROM子句或擁有FROM DUAL子句時出現。例如:explain select 1

◦Not exists:MySQL能對LEFT JOIN優化,在找到符合LEFT JOIN的行後,不會為上一行組合中檢查此表中的更多行。例如:

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id
WHERE t2.id IS NULL;

◦假設t2.id定義成了NOT NULL ,此時,MySQL會掃描t1,並使用t1.id的值查找t2中的行。 如果MySQL在t2中找到一個匹配的行,它會知道t2.id永遠不會為NULL,並且不會掃描t2中具有相同id值的其餘行。也就是說,對於t1中的每一行,MySQL只需要在t2中只執行一次查找,而不考慮在t2中實際匹配的行數。

◦在MySQL 8.0.17及更高版本中,如果出現此提示,還可表示形如 NOT IN (subquery) 或 NOT EXISTS (subquery) 的WHERE條件已經在內部轉換為反連接。這將刪除子查詢並將其表放入最頂層的查詢計劃中,從而改進查詢的開銷。通過合併半連接和反聯接,優化器可以更加自由地對執行計劃中的表重新排序,在某些情況下,可讓查詢提速。你可以通過在EXPLAIN語句後緊跟一個SHOW WARNING語句,並分析結果中的Message列,從而查看何時對該查詢執行了反聯接轉換。

◦Note:兩表關聯只返回主表的數據,並且只返回主表與子表沒關聯上的數據,這種連接就叫反連接Plan isn’t ready yet:使用了EXPLAIN FOR CONNECTION,當優化器尚未完成為在指定連接中為執行的語句創建執行計劃時, 就會出現此值。MySQL沒有找到合適的索引去使用,但是去檢查是否可以使用range或index_merge來檢索行時,會出現此提示。index map N索引的編號從1開始,按照與表的SHOW INDEX所示相同的順序。 索引映射值N是指示哪些索引是候選的位掩碼值。 例如0x19(二進位11001)的值意味著將考慮索引1、4和5。

  • Plan isn’t ready yet:使用了EXPLAIN FOR CONNECTION,當優化器尚未完成為在指定連接中為執行的語句創建執行計劃時, 就會出現此值。

◦MySQL沒有找到合適的索引去使用,但是去檢查是否可以使用range或index_merge來檢索行時,會出現此提示。index map N索引的編號從1開始,按照與表的SHOW INDEX所示相同的順序。 索引映射值N是指示哪些索引是候選的位掩碼值。 例如0x19(二進位11001)的值意味著將考慮索引1、4和5。

◦示例:下麵例子中,name是varchar類型,但是條件給出整數型,涉及到隱式轉換。圖中t2也沒有用到索引,是因為查詢之前我將t2中name欄位排序規則改為utf8_bin導致的鏈接欄位排序規則不匹配。

explain select a.* from t1 a left  join t2 b
on t1.name = t2.name
where t2.name = 2;
  • 結果:

  • Recursive:出現了遞歸查詢。詳見“WITH (Common Table Expressions)”
  • Rematerialize:用得很少,使用類似如下SQL時,會展示Rematerialize
SELECT
  ...
FROM
  t,
  LATERAL (derived table that refers to t) AS dt
...
  • Scanned N databases:表示在處理INFORMATION_SCHEMA表的查詢時,掃描了幾個目錄,N的取值可以是0,1或者all。詳見 “Optimizing INFORMATION_SCHEMA Queries”
  • Select tables optimized away:優化器確定:①最多返回1行;②要產生該行的數據,要讀取一組確定的行,時會出現此提示。一般在用某些聚合函數訪問存在索引的某個欄位時,優化器會通過索引直接一次定位到所需要的數據行完成整個查詢時展示,例如下麵這條SQL。
explain
select min(id)
from t1;
  • Skip_open_table, Open_frm_only, Open_full_table:這些值表示適用於INFORMATION_SCHEMA表查詢的文件打開優化;

◦Skip_open_table:無需打開表文件,信息已經通過掃描數據字典獲得

◦Open_frm_only:僅需要讀取數據字典以獲取表信息

◦Open_full_table:未優化的信息查找。表信息必須從數據字典以及表文件中讀取Start temporary, End temporary:表示臨時表使用Duplicate Weedout策略,詳見 https://mariadb.com/kb/en/duplicateweedout-strategy/ ,翻譯 https://www.cnblogs.com/abclife/p/10895531.html

  • unique row not found:對於形如 SELECT … FROM tbl_name 的查詢,但沒有行能夠滿足唯一索引或主鍵查詢的條件
  • Using filesort:當Query 中包含 ORDER BY 操作,而且無法利用索引完成排序操作的時候,MySQL Query Optimizer 不得不選擇相應的排序演算法來實現。數據較少時從記憶體排序,否則從磁碟排序。Explain不會顯示的告訴客戶端用哪種排序。官方解釋:“MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接類型瀏覽所有行併為所有匹配WHERE子句的行保存排序關鍵字和行的指針來完成排序。然後關鍵字被排序,並按排序順序檢索行”Using index:僅使用索引樹中的信息從表中檢索列信息,而不必進行其他查找以讀取實際行。當查詢僅使用屬於單個索引的列時,可以使用此策略。例如:explain SELECT id FROM t
  • Using index condition:表示先按條件過濾索引,過濾完索引後找到所有符合索引條件的數據行,隨後用 WHERE 子句中的其他條件去過濾這些數據行。通過這種方式,除非有必要,否則索引信息將可以延遲“下推”讀取整個行的數據。詳見 “Index Condition Pushdown Optimization” 。例如:
  • MySQL分成了Server層和引擎層,下推指的是將請求交給引擎層處理。理解這個功能,可創建所以INDEX (zipcode, lastname, firstname),並分別用如下指令,
SET optimizer_switch = 'index_condition_pushdown=off'; 
SET optimizer_switch = 'index_condition_pushdown=on';
  • 開或者關閉索引條件下推,並對比:
explain SELECT * FROM people
WHERE zipcode='95054'
AND lastname LIKE '%etrunia%'
AND address LIKE '%Main Street%';
  • 的執行結果。index condition pushdown從MySQL 5.6開始支持,是MySQL針對特定場景的優化機制,感興趣的可以看下 https://blog.51cto.com/lee90/2060449
  • Using index for group-by:數據訪問和 Using index 一樣,所需數據只須要讀取索引,當Query 中使用GROUP BY或DISTINCT 子句時,如果分組欄位也在索引中,Extra中的信息就會是 Using index for group-by。詳見 “GROUP BY Optimization”
-- name欄位有索引
explain SELECT name FROM t1 group by name
  • Using index for skip scan:表示使用了Skip Scan。詳見 Skip Scan Range Access Method
  • Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access):使用Block Nested Loop或Batched Key Access演算法提高join的性能。詳見 https://www.cnblogs.com/chenpingzhao/p/6720531.html
  • Using MRR:使用了Multi-Range Read優化策略。詳見 “Multi-Range Read Optimization”Using sort_union(…), Using union(…), Using intersect(…):這些指示索引掃描如何合併為index_merge連接類型。詳見 “Index Merge Optimization”
  • Using temporary:為瞭解決該查詢,MySQL需要創建一個臨時表來保存結果。如果查詢包含不同列的GROUP BY和 ORDER BY子句,通常會發生這種情況。
-- name無索引
explain SELECT name FROM t1 group by name
  • Using where:如果我們不是讀取表的所有數據,或者不是僅僅通過索引就可以獲取所有需要的數據,則會出現using where信息
explain SELECT * FROM t1 where id > 5
  • Using where with pushed condition:僅用於NDB
  • Zero limit:該查詢有一個limit 0子句,不能選擇任何行explain SELECT name FROM resource_template limit 0

4. 擴展的EXPLAIN

  • EXPLAIN可產生額外的擴展信息,可通過在EXPLAIN語句後緊跟一條SHOW WARNING語句查看擴展信息。
  • TIPS

在MySQL 8.0.12及更高版本,擴展信息可用於SELECT、DELETE、INSERT、REPLACE、UPDATE語句;在MySQL 8.0.12之前,擴展信息僅適用於SELECT語句; 在MySQL 5.6及更低版本,需使用EXPLAIN EXTENDED xxx語句;而從MySQL 5.7開始,無需添加EXTENDED關鍵詞。

  • 使用示例:
mysql> EXPLAIN
   SELECT t1.a, t1.a IN (SELECT t2.a FROM t2) FROM t1\G
*************************** 1. row ***************************
          id: 1
  select_type: PRIMARY
        table: t1
        type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
        rows: 4
    filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
          id: 2
  select_type: SUBQUERY
        table: t2
        type: index
possible_keys: a
          key: a
      key_len: 5
          ref: NULL
        rows: 3
    filtered: 100.00
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
  Code: 1003
Message: /* select#1 */ select `test`.`t1`.`a` AS `a`,
        <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in
        ( <materialize> (/* select#2 */ select `test`.`t2`.`a`
        from `test`.`t2` where 1 having 1 ),
        <primary_index_lookup>(`test`.`t1`.`a` in
        <temporary table> on <auto_key>
        where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) AS `t1.a
        IN (SELECT t2.a FROM t2)` from `test`.`t1`
1 row in set (0.00 sec)
  • 由於SHOW WARNING的結果並不一定是一個有效SQL,也不一定能夠執行(因為裡面包含了很多特殊標記)。特殊標記取值如下:

◦<auto_key>:自動生成的臨時表key

(expr):表達式(例如標量子查詢)執行了一次,並且將值保存在了記憶體中以備以後使用。對於包括多個值的結果,可能會創建臨時表,你將會看到 的字樣

(query fragment):子查詢被轉換為 EXISTS

◦<in_optimizer>(query fragment):這是一個內部優化器對象,對用戶沒有任何意義

◦<index_lookup>(query fragment):使用索引查找來處理查詢片段,從而找到合格的行

(condition, expr1, expr2):如果條件是true,則取expr1,否則取expr2

◦<is_not_null_test>(expr):驗證表達式不為NULL的測試

(query fragment):使用子查詢實現

◦materialized-subquery.col_name:在內部物化臨時表中對col_name的引用,以保存子查詢的結果

◦<primary_index_lookup>(query fragment):使用主鍵來處理查詢片段,從而找到合格的行

◦<ref_null_helper>(expr):這是一個內部優化器對象,對用戶沒有任何意義

◦/* select#N */ select_stmt:SELECT與非擴展的EXPLAIN輸出中id=N的那行關聯

◦outer_tables semi join (inner_tables):半連接操作。inner_tables展示未拉出的表。詳見 “Optimizing Subqueries, Derived Tables, and View References with Semijoin Transformations”

:表示創建了內部臨時表而緩存中間結果

  • 當某些表是const或system類型時,這些表中的列所涉及的表達式將由優化器儘早評估,並且不屬於所顯示語句的一部分。但是,當使用FORMAT=JSON時,某些const表的訪問將顯示為ref。

5. 估計查詢性能

  • 多數情況下,你可以通過計算磁碟的搜索次數來估算查詢性能。對於比較小的表,通常可以在一次磁碟搜索中找到行(因為索引可能已經被緩存了),而對於更大的表,你可以使用B-tree索引進行估算:你需要進行多少次查找才能找到行:log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1
  • 在MySQL中,index_block_length通常是1024位元組,數據指針一般是4位元組。比方說,有一個500,000的表,key是3位元組,那麼根據計算公式 log(500,000)/log(1024/3*2/(3+4)) + 1 = 4 次搜索。
  • 該索引將需要500,000 * 7 * 3/2 = 5.2MB的存儲空間(假設典型的索引緩存的填充率是2/3),因此你可以在記憶體中存放更多索引,可能只要一到兩個調用就可以找到想要的行了。
  • 但是,對於寫操作,你需要四個搜索請求來查找在何處放置新的索引值,然後通常需要2次搜索來更新索引並寫入行。
  • 前面的討論並不意味著你的應用性能會因為log N而緩慢下降。只要內容被OS或MySQL伺服器緩存,隨著表的變大,只會稍微變慢。在數據量變得太大而無法緩存後,將會變慢很多,直到你的應用程式受到磁碟搜索約束(按照log N增長)。為了避免這種情況,可以根據數據的增長而增加key的。對於MyISAM表,key的緩存大小由名為key_buffer_size的系統變數控制,詳見Section 5.1.1, “Configuring the Server”

6. 參考文檔

作者:京東物流 柳巨集

來源:京東雲開發者社區 自猿其說Tech   轉載請註明來源


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

-Advertisement-
Play Games
更多相關文章
  • 本文將詳細介紹如何發佈.NET Core項目到IIS伺服器。首先,第一步需要安裝IIS,介紹了在本地電腦和伺服器中進行安裝。然後需要安裝SDK和運行時才能發佈.NETCore項目。其次介紹瞭如何發佈.NETCore項目和Vue項目,並配置IIS。最後介紹瞭如何將項目部署到Service服務中。 ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202308/3076680-20230815092340479-67825278.png) # 1. 事務日誌 ## 1.1. 事務日誌有助於提高事務的效率 ### 1.1.1. 存儲引擎只需要更改記憶體中的數 ...
  • # mysql複製技術/mysql集群 ![](https://img2023.cnblogs.com/blog/3165277/202308/3165277-20230815183932805-1063237772.png) ## 準備 1.四台虛擬機都關閉防火牆 ``` systemctl st ...
  • 最近系統有個需求,希望工作流的審批人被催辦後就要置頂在最前面, 工作流列表我是用es的,一開始想用pinned實現,但用pinned的話,每頁都會置頂在前面,我的需求只是想讓他優先排在前面,翻頁後正常顯示 後面找到這個,通過把匹配到數據的分數提高,然後用sort進行排序,就能實現我的需求了 GET ...
  • 簡介 Timescale Documentation | Getting started with Timescale Timescale是一個用於時間序列,事件和分析的PostgreSQL數據平臺。 提供了PostgreSQL的可靠性,這是時間序列的超能力 TimescaleDB,。它提供 自動備 ...
  • GaussDB(for Influx)推出了單機版方案,可用於開發、測試等場景,既能享受到服務化帶來的便利,也可以明顯地降低使用成本。 ...
  • 說到分散式事務,大家並不陌生。在實際工作中,用得比較多的還是柔性分散式事務,今天主要把在工作中運用到的幾種柔性分散式事務的場景及實現方式做一個簡單介紹,也可以看做是柔性分散式事務的一個演進過程。 ...
  • 本文是一次工作中對併發問題的處理案例,問題發生在快遞分揀的流程中,我儘可能將業務背景簡化,讓大家只關註併發問題本身。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...