mysql優化---訂單查詢優化:視圖優化+索引創建

来源:http://www.cnblogs.com/victor2302/archive/2016/11/17/6073821.html
-Advertisement-
Play Games

訂單的表結構採用了垂直分表的策略,將訂單相關的不同模塊的欄位維護在不同表中 在訂單處理這個頁面,需要查詢各種維度, 因此為了方便查詢創建了v_sale_order視圖(老版本) 之前的代碼(老版本): DEFAULT_FILTER是訂單處理裡面,固定的查詢條件,每次查詢都會有該部分條件,但是sql的 ...


訂單的表結構採用了垂直分表的策略,將訂單相關的不同模塊的欄位維護在不同表中

在訂單處理這個頁面,需要查詢各種維度,

因此為了方便查詢創建了v_sale_order視圖(老版本)

drop view v_sale_order;
CREATE
VIEW `v_sale_order` AS
SELECT
    `so`.`sale_order_id` AS `v_sale_order_id`,
    `so`.`sale_order_id` AS `sale_order_id`,
    `so`.`sale_order_no` AS `sale_order_no`,
    `so`.`order_type` AS `order_type`,
    `so`.`platform_order_code2` AS `platform_order_code2`,
    `so`.`platform_order_code` AS `platform_order_code`,
    `so`.`platform_type` AS `platform_type`,
    `so`.`platform_order_status` AS `platform_order_status`,
    `so`.`created` AS `created`,
    `so`.`end_time` AS `end_time`,
    `so`.`total_num` AS `total_num`,
    `so`.`total_sku` AS `total_sku`,
    `so`.`modified` AS `modified`,
    `so`.`seller_flag` AS `seller_flag`,
    `so`.`seller_memo` AS `seller_memo`,
    `so`.`seller_rate` AS `seller_rate`,
    `so`.`snapshot_url` AS `snapshot_url`,
    `so`.`status` AS `status`,
    `so`.`step_trade_status` AS `step_trade_status`,
    `so`.`trade_from` AS `trade_from`,
    `so`.`trade_memo` AS `trade_memo`,
    `so`.`trade_source` AS `trade_source`,
    `so`.`type` AS `type`,
    `so`.`shop_id` AS `shop_id`,
    `so`.`origin_type` AS `origin_type`,
    `so`.`sys_promotion_info` AS `sys_promotion_info`, 
    `sor`.`buyer_area` AS `buyer_area`,
    `sor`.`buyer_email` AS `buyer_email`,
    `sor`.`buyer_ip` AS `buyer_ip`,
    `sor`.`buyer_memo` AS `buyer_memo`,
    `sor`.`buyer_message` AS `buyer_message`,
    `sor`.`buyer_nick` AS `buyer_nick`,
    `sor`.`buyer_rate` AS `buyer_rate`,
    `sor`.`receiver_address` AS `receiver_address`,
    `sor`.`receiver_city` AS `receiver_city`,
    `sor`.`receiver_country` AS `receiver_country`,
    `sor`.`receiver_district` AS `receiver_district`,
    `sor`.`receiver_mobile` AS `receiver_mobile`,
    `sor`.`receiver_name` AS `receiver_name`,
    `sor`.`receiver_phone` AS `receiver_phone`,
    `sor`.`receiver_state` AS `receiver_state`,
    `sor`.`receiver_town` AS `receiver_town`,
    `sor`.`receiver_zip` AS `receiver_zip`,
    `sor`.`area_id` AS `area_id`,
    `sor`.`customer_id` AS `customer_id`,
    `soc`.`courier_id` AS `courier_id`,
    `soc`.`courier_order_no` AS `courier_order_no`,
    `soc`.`courier_print_mark_state` AS `courier_print_mark_state`,
    `soc`.`courier_print_time` AS `courier_print_time`,
    `sof`.`alipay_id` AS `alipay_id`,
    `sof`.`alipay_no` AS `alipay_no`,
    `sof`.`payment` AS `payment`,
    `sof`.`total_fee` AS `total_fee`,
    `soi`.`invoice_order_no` AS `invoice_order_no`,
    `soi`.`invoice_content` AS `invoice_content`,
    `soi`.`invoice_type` AS `invoice_type`,
    `soi`.`bank` AS `bank`,
    `soi`.`title` AS `title`,
    `soi`.`bank_account` AS `bank_account`,
    `soi`.`tariff_lines` AS `tariff_lines`,
    `sos`.`oms_process_type` AS `oms_process_type`,
    `sos`.`play_state` AS `play_state`,
    `sos`.`pause_state` AS `pause_state`,
    `sos`.`stop_state` AS `stop_state`,
    `sos`.`archive_state` AS `archive_state`,
    `sos`.`is_paid` AS `is_paid`,
    `sos`.`is_checked` AS `is_checked`,
    `sos`.`is_approved` AS `is_approved`,
    `sos`.`is_suspended` AS `is_suspended`,
    `sos`.`is_invalidated` AS `is_invalidated`,
    `sos`.`is_to_be_shipped` AS `is_to_be_shipped`,
    `sos`.`is_after_sale` AS `is_after_sale`,
    `sos`.`is_split` AS `is_split`,
    `sos`.`is_combined` AS `is_combined`,
    `sos`.`is_closed` AS `is_closed`,
    `sos`.`is_after_sale_closed` AS `is_after_sale_closed`,
    `sos`.`is_amount_changed` AS `is_amount_changed`,
    `sos`.`is_part_changed` AS `is_part_changed`,
    `sos`.`is_out_of_stock` AS `is_out_of_stock`,
    `sos`.`pay_type` AS `pay_type`,
    `sos`.`pay_time` AS `pay_time`,
    `sos`.`original_order_id` AS `original_order_id`,
    `sos`.`after_sale_note` AS `after_sale_note`,
    `sos`.`suspend_note` AS `suspend_note`,
    `sos`.`unapprove_note` AS `unapprove_note`,
    `sos`.`after_sale_type` AS `after_sale_type`,
    `sos`.`blacklist_type` AS `blacklist_type`, 
    `sow`.`warehouse_id` AS `warehouse_id`,
    `sow`.`retry_num` AS `retry_num`,
    `sow`.`out_warehouse_time` AS `out_warehouse_time`,
    `sow`.`purchase_order_no` AS `purchase_order_no`,
    `sow`.`purchase_order_id` AS `purchase_order_id`,
    `sow`.`wms_order_state` AS `wms_order_state`,
    `sow`.`checked_time` AS `checked_time`,
    `so`.`creator` AS `creator`,
    `so`.`create_time` AS `create_time`,
    `so`.`last_updater` AS `last_updater`,
    `so`.`last_update_time` AS `last_update_time`,
    `so`.`is_usable` AS `is_usable`,
    `so`.`tenant_id` AS `tenant_id`
FROM
    (
        (
            (
                (
                    (
                        (
                            `sale_order` `so`
                            LEFT JOIN `sale_order_receiver` `sor` ON (
                                (
                                    `so`.`sale_order_id` = `sor`.`sale_order_id`
                                )
                            )
                        )
                        LEFT JOIN `sale_order_status` `sos` ON (
                            (
                                `so`.`sale_order_id` = `sos`.`sale_order_id`
                            )
                        )
                    )
                    LEFT JOIN `sale_order_warehouse` `sow` ON (
                        (
                            `so`.`sale_order_id` = `sow`.`sale_order_id`
                        )
                    )
                )
                LEFT JOIN `sale_order_courier` `soc` ON (
                    (
                        `so`.`sale_order_id` = `soc`.`sale_order_id`
                    )
                )
            )
            LEFT JOIN `sale_order_invoice` `soi` ON (
                (
                    `so`.`sale_order_id` = `soi`.`sale_order_id`
                )
            )
        )
        LEFT JOIN `sale_order_finance` `sof` ON (
            (
                `so`.`sale_order_id` = `sof`.`sale_order_id`
            )
        )
    );

 

之前的代碼(老版本):

@Service
public class OrderService extends TemplateService {

    public static final String DEFALUT_FILTER = " AND NOT(is_split = 1 AND archive_state=3) AND NOT(is_combined = 1 AND archive_state=4) " +
            " AND NOT(oms_process_type =0) AND (v_sale_order.platform_order_status != 'TRADE_FINISHED' OR origin_type=2) " +
            "AND NOT is_invalidated=1" +
            " AND NOT archive_state=5 AND NOT archive_state=6";
    public static final String HISTORY_FILTER = " AND NOT(is_split = 1 AND archive_state=3) AND NOT(is_combined = 1 AND archive_state=4) " +
        " AND NOT archive_state=5 AND NOT archive_state=6"; }

DEFAULT_FILTER是訂單處理裡面,固定的查詢條件,每次查詢都會有該部分條件,但是sql的寫法包含了太多OR,NOT,!= 等操作

優化第一步:  根據業務規則合併一些欄位,將一些排除條件改為正向命中的條件(第二版):


@Service public class OrderService extends TemplateService { /** 訂單處理: 過濾掉:合併拆分的訂單 過濾掉:交易完成或交易關閉 要求:跑過預處理 要求:已付款或者貨到付款 要求:未作廢的 */ public static final String DEFALUT_FILTER = " AND archive_state IN (0, 1) AND v_sale_order.is_paid = 1 AND oms_process_type = 1 " + " AND v_sale_order.is_invalidated=0 AND is_closed = 0"; /** * 訂單查詢: * 過濾掉:合併拆分的訂單 */ public static final String HISTORY_FILTER = " AND archive_state IN (0, 1)"; public static final String AFTER_FILTER = " AND archive_state IN (0,1,2) AND is_paid=1"; }

 

優化第二步:   訂單處理相比訂單查詢多了很多固定條件,大部分處於sale_order_status表中,但是之前視圖的創建方式固定了最左邊的表,因此修改視圖創建的腳本,如下:

從固定的left join改為 Join

CREATE OR REPLACE VIEW v_sale_order AS
  SELECT
    `so`.`sale_order_id`             AS `v_sale_order_id`,
    `so`.`sale_order_id`             AS `sale_order_id`,
    `so`.`sale_order_no`             AS `sale_order_no`,
    `so`.`order_type`                AS `order_type`,
    `so`.`platform_order_code2`      AS `platform_order_code2`,
    `so`.`platform_order_code`       AS `platform_order_code`,
    `so`.`platform_type`             AS `platform_type`,
    `so`.`platform_order_status`     AS `platform_order_status`,
    `so`.`created`                   AS `created`,
    `so`.`end_time`                  AS `end_time`,
    `so`.`total_num`                 AS `total_num`,
    `so`.`total_sku`                 AS `total_sku`,
    `so`.`modified`                  AS `modified`,
    `so`.`seller_flag`               AS `seller_flag`,
    `so`.`seller_memo`               AS `seller_memo`,
    `so`.`seller_rate`               AS `seller_rate`,
    `so`.`snapshot_url`              AS `snapshot_url`,
    `so`.`status`                    AS `status`,
    `so`.`step_trade_status`         AS `step_trade_status`,
    `so`.`trade_from`                AS `trade_from`,
    `so`.`trade_memo`                AS `trade_memo`,
    `so`.`trade_source`              AS `trade_source`,
    `so`.`type`                      AS `type`,
    `so`.`shop_id`                   AS `shop_id`,
    `so`.`origin_type`               AS `origin_type`,
    `so`.`sys_promotion_info`        AS `sys_promotion_info`,
    `sor`.`buyer_area`               AS `buyer_area`,
    `sor`.`buyer_email`              AS `buyer_email`,
    `sor`.`buyer_ip`                 AS `buyer_ip`,
    `sor`.`buyer_memo`               AS `buyer_memo`,
    `sor`.`buyer_message`            AS `buyer_message`,
    `sor`.`buyer_nick`               AS `buyer_nick`,
    `sor`.`buyer_rate`               AS `buyer_rate`,
    `sor`.`receiver_address`         AS `receiver_address`,
    `sor`.`receiver_city`            AS `receiver_city`,
    `sor`.`receiver_country`         AS `receiver_country`,
    `sor`.`receiver_district`        AS `receiver_district`,
    `sor`.`receiver_mobile`          AS `receiver_mobile`,
    `sor`.`receiver_name`            AS `receiver_name`,
    `sor`.`receiver_phone`           AS `receiver_phone`,
    `sor`.`receiver_state`           AS `receiver_state`,
    `sor`.`receiver_town`            AS `receiver_town`,
    `sor`.`receiver_zip`             AS `receiver_zip`,
    `sor`.`area_id`                  AS `area_id`,
    `sor`.`customer_id`              AS `customer_id`,
    `soc`.`courier_id`               AS `courier_id`,
    `soc`.`courier_order_no`         AS `courier_order_no`,
    `soc`.`courier_print_mark_state` AS `courier_print_mark_state`,
    `soc`.`courier_print_time`       AS `courier_print_time`,
    `sof`.`alipay_id`                AS `alipay_id`,
    `sof`.`alipay_no`                AS `alipay_no`,
    `sof`.`payment`                  AS `payment`,
    `sof`.`total_fee`                AS `total_fee`,
    `soi`.`invoice_order_no`         AS `invoice_order_no`,
    `soi`.`invoice_content`          AS `invoice_content`,
    `soi`.`invoice_type`             AS `invoice_type`,
    `soi`.`bank`                     AS `bank`,
    `soi`.`title`                    AS `title`,
    `soi`.`bank_account`             AS `bank_account`,
    `soi`.`tariff_lines`             AS `tariff_lines`,
    `sos`.`oms_process_type`         AS `oms_process_type`,
    `sos`.`play_state`               AS `play_state`,
    `sos`.`pause_state`              AS `pause_state`,
    `sos`.`stop_state`               AS `stop_state`,
    `sos`.`archive_state`            AS `archive_state`,
    `sos`.`is_paid`                  AS `is_paid`,
    `sos`.`is_checked`               AS `is_checked`,
    `sos`.`is_approved`              AS `is_approved`,
    `sos`.`is_suspended`             AS `is_suspended`,
    `sos`.`is_invalidated`           AS `is_invalidated`,
    `sos`.`is_to_be_shipped`         AS `is_to_be_shipped`,
    `sos`.`is_after_sale`            AS `is_after_sale`,
    `sos`.`is_split`                 AS `is_split`,
    `sos`.`is_combined`              AS `is_combined`,
    `sos`.`is_closed`                AS `is_closed`,
    `sos`.`is_after_sale_closed`     AS `is_after_sale_closed`,
    `sos`.`is_amount_changed`        AS `is_amount_changed`,
    `sos`.`is_part_changed`          AS `is_part_changed`,
    `sos`.`is_out_of_stock`          AS `is_out_of_stock`,
    `sos`.`pay_type`                 AS `pay_type`,
    `sos`.`pay_time`                 AS `pay_time`,
    `sos`.`original_order_id`        AS `original_order_id`,
    `sos`.`after_sale_note`          AS `after_sale_note`,
    `sos`.`suspend_note`             AS `suspend_note`,
    `sos`.`unapprove_note`           AS `unapprove_note`,
    `sos`.`after_sale_type`          AS `after_sale_type`,
    `sos`.`blacklist_type`           AS `blacklist_type`,
    `sow`.`warehouse_id`             AS `warehouse_id`,
    `sow`.`retry_num`                AS `retry_num`,
    `sow`.`out_warehouse_time`       AS `out_warehouse_time`,
    `sow`.`purchase_order_no`        AS `purchase_order_no`,
    `sow`.`purchase_order_id`        AS `purchase_order_id`,
    `sow`.`wms_order_state`          AS `wms_order_state`,
    `sow`.`checked_time`             AS `checked_time`,
    `so`.`creator`                   AS `creator`,
    `sos`.`create_time`              AS `create_time`,
    `so`.`last_updater`              AS `last_updater`,
    `sos`.`last_update_time`         AS `last_update_time`,
    `sos`.`is_usable`                AS `is_usable`,
    `sos`.`tenant_id`                AS `tenant_id`
  FROM ((((((`sale_order_status` `sos`
    JOIN `sale_order_receiver` `sor` ON ((`sos`.`sale_order_id` = `sor`.`sale_order_id`))) JOIN
    `sale_order` `so` ON ((`so`.`sale_order_id` = `sos`.`sale_order_id`))) JOIN
    `sale_order_warehouse` `sow` ON ((`sos`.`sale_order_id` = `sow`.`sale_order_id`))) JOIN
    `sale_order_courier` `soc` ON ((`sos`.`sale_order_id` = `soc`.`sale_order_id`))) JOIN
    `sale_order_finance` `sof` ON ((`sos`.`sale_order_id` = `sof`.`sale_order_id`))) LEFT JOIN
    `sale_order_invoice` `soi` ON ((`sos`.`sale_order_id` = `soi`.`sale_order_id`))) 

最左邊表可根據查詢條件動態的變化,(如條件過濾查詢sale_order_courier的courier_id欄位, where courier_id= xx,並且sale_order_courier的courier_id欄位上已經建立了索引,那麼explain後第一個查詢的表就是sale_order_courier)

之前sale_order表始終作為v_sale_order實際查詢時的第一個表,而無法走索引

(P.S.本人目前的理解:mysql多表關聯查詢只有最左邊表可以走索引,其餘表的索引只能是關聯的id作為索引) 

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1 SIMPLE sos ref idx_sale_order_id,oms_normal_v2,oms_check_v2,oms_suspend_v2 oms_check_v2 10 const,const,const,const 271 Using where; Using filesort
1 SIMPLE sor ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE soc ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE sof ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE so eq_ref PRIMARY PRIMARY 8 egenie.sos.sale_order_id 1 NULL
1 SIMPLE sow ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE soi ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL

 

 

隨後創建的索引(第一版),生效

--archive_state in()結果太多 走不了索引
CREATE INDEX oms_normal on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,last_update_time);

CREATE INDEX oms_check on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,
is_checked,last_update_time);

CREATE INDEX oms_suspend on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,
is_suspended,last_update_time);

--sale_order
CREATE INDEX shop_idx on sale_order(shop_id,order_type);
CREATE INDEX platform_idx on sale_order(platform_order_status,order_type);

--sale_order_warehouse
CREATE INDEX warehouse_idx on sale_order_warehouse(warehouse_id);

--sale_order_courier
CREATE INDEX courier_idx on sale_order_courier(courier_id);

 

由於有新需求需要改造固定的查詢sql(第三版)

@Service
public class OrderService extends TemplateService {

    private static final String isPaySql = " AND (is_paid = 1 OR pay_type = 4 ) ";
    /**
     * 訂單處理:
     * 過濾掉:合併拆分的訂單
     * 過濾掉:交易完成或交易關閉
     * 要求:跑過預處理
     * 要求:已付款或者貨到付款
     * 要求:未作廢的
     */
    public static final String DEFALUT_FILTER = " AND archive_state IN (0, 1)  AND oms_process_type = 1 " +
            isPaySql + " AND v_sale_order.is_invalidated=0 AND is_closed = 0";
    /**
     * 訂單查詢:
     * 過濾掉:合併拆分的訂單
     */
    public static final String HISTORY_FILTER = " AND archive_state IN (0, 1)";
    public static final String AFTER_FILTER = " AND archive_state IN (0,1,2) " + isPaySql;
    }

改進:

1.將之前的is_paid 移除之前的索引

2.調整索引的順序,移除毫無辨識度的欄位

 (第二版)

CREATE INDEX oms_normal_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,last_update_time);

CREATE INDEX oms_check_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,is_checked,last_update_time);

CREATE INDEX oms_suspend_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,is_suspended,last_update_time);

 


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

-Advertisement-
Play Games
更多相關文章
  • mysql 官方客戶端 MySQL-Workbench 下載鏈接 http://dev.mysql.com/downloads/workbench/ 具體安裝步驟就不寫了,直接一直下一步就可以了。 下麵說一下基礎操作: 登錄成功後,界面如下所示。其中,區域1顯示的是資料庫伺服器中已經創建的資料庫列表 ...
  • 前面的話 由於編碼錯誤,造成的資料庫中文識別成亂碼或問號的問題非常常見,本文將詳細說明解決辦法 配置文件 解決中文識別問題的第一步是修改mysql的配置文件my.ini 在[client]下添加 在[mysqld]下添加 然後重新啟動服務 資料庫編碼 首先,新建一個資料庫 通過下列代碼查看資料庫的編 ...
  • 由於SQL優化優化起來比較複雜,並且還受環境限制,在開發過程中,寫SQL必須遵循以下幾點原則: 1.Oracle 採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾. 2.Select 語句避免 ...
  • 最近一直在跟Oracle打交道,從最初的一臉懵逼到現在的略有所知,也來總結一下自己最近所學,不定時更新ing… 一:什麼是Oracle執行計劃? 執行計劃是一條查詢語句在Oracle中的執行過程或訪問路徑的描述 二:怎樣查看Oracle執行計劃? 因為我一直用的PLSQL遠程連接的公司資料庫,所以這 ...
  • SQL server基礎知識 一、基礎知識 (1)、存儲結構:資料庫->表->數據 (2)、管理資料庫 增加:create database 資料庫名稱 刪除:drop database 資料庫名稱 查詢:select name from master..sysdatabases 修改:alter ...
  • [1]插入記錄 [2]更新記錄 [3]刪除記錄 [4]查詢表達式 [5]結果處理 ...
  • 環境:CentOS6.8 Mongodb3.2.10 啟動 啟動mongoDB伺服器 # service mongod start 啟動mongoDB客戶端 # mongo 該客戶端是一個JavaScript shell,我們可以直接在裡面寫js的代碼,並執行。該客戶端在安裝mongoDB時是可選的... ...
  • 在大數據的當下,各種spark和hadoop的框架層出不窮。各種高端的計算框架,分散式任務如亂花般迷眼。你是否有這種困惑!——有了許多的分散式任務,但是每天需要固定時間跑任務,自己寫個調度,既不穩定,又沒有可靠的通知。 想要瞭解 "Oozie的基礎知識,可以參考這裡" 那麼你應該是在找——Oozie ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...