MySql中執行計劃如何來的——Optimizer Trace

来源:https://www.cnblogs.com/Jcloud/archive/2023/04/26/17355705.html
-Advertisement-
Play Games

當談到MySQL的執行計劃時,會有很多同學想:“我就覺得使用其他的執行方案比EXPLAIN語句輸出的方案強,憑什麼優化器做的決定與我得不一樣?”。這個問題在MySQL 5.6之前或許自己很難解決,但是現在MySQL5.6及更高的版本中引入了Optimizer Trace。 ...


作者:京東物流 籍磊

1.前言

當談到MySQL的執行計劃時,會有很多同學想:“我就覺得使用其他的執行方案比EXPLAIN語句輸出的方案強,憑什麼優化器做的決定與我得不一樣?”。這個問題在MySQL 5.6之前或許自己很難解決,但是現在MySQL5.6及更高的版本中引入了Optimizer Trace。

2.optimizer_trace開啟方式及表結構

當下麵這行代碼執行的時候會將會使用戶能夠方便地查看優化器生成執行計劃的整個過程。

SET SESSION optimizer_trace=”enabled=on”;

optimizer_trace的開關預設是關閉的,我們可以使用下行代碼查看optimizer_trace狀態。

SHOW variables LIKE'optimizer_trace';

其中one_line值是用來控制輸出格式的,如果值為on,那所有的信息會在同一行中展示(這樣並不便於我們閱讀),預設為off。當我們的optimizer_trace的enabled為on時,輸入想要查看優化過程的查詢語句,在該語句執行完之後,就可以到information_schema資料庫下的optimizer_trace表中查看詳細的執行計劃生成過程,當然也可以直接對想要的查詢語句使用EXPLAIN。

optimizer_trace表有四列,每列註釋我補充在下方create語句中:

CREATE TEMPORARY TABLE `OPTIMIZER_TRACE` (
  `QUERY` longtext NOT NULL COMMENT '我們輸入的查詢語句',
  `TRACE` longtext NOT NULL COMMENT '優化過程的json文本',
  `MISSING_BYTES_BEYOND_MAX_MEM_SIZE` int(20) NOT NULL DEFAULT '0' COMMENT '執行計劃生成
的過程中產生的超出字數限制的文本數',
  `INSUFFICIENT_PRIVILEGES` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否有許可權查看執行
計劃的生成過程,0有許可權,1無許可權'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

3.optimizer_trace實踐

我們現在根據一個例子來看看optimizer_trace的實踐。

explain select * from ship_data.check_table 
where 
outbound_no ='ESL48400163536608' and 
yn=0 and 
update_user ='jilei18';
SELECT * FROM information_schema.OPTIMIZER_TRACE;

上述sql的執行計劃如下:

OPTIMIZER_TRACE表中的信息,這裡可以註意到MISSING_BYTES_BEYOND_MAX_MEM_SIZE的值為1023,說明TRACE中並沒有顯示出全部的優化過程:

Query列中的文本是我們執行的Sql語句:

/* ApplicationName=DBeaver 21.1.3 - SQLEditor <Script-2.sql> */ explain select * from ship_data.check_table 
where 
outbound_no ='ESL48400163536608' and 
yn=0 and 
update_user ='jilei18'

TRACE列是優化的具體過程,其中分析過程需要註意的點在下麵代碼框中使用#註釋的形式給出:

{
  "steps": [
    {
      "join_preparation": { #prepare階段
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `ship_data`.`check_table`.`m_id` AS `m_id`,`ship_data`.`check_table`.`wave_no` AS `wave_no`,`ship_data`.`check_table`.`wave_type` AS `wave_type`,`ship_data`.`check_table`.`outbound_no` AS `outbound_no`,`ship_data`.`check_table`.`outbound_type` AS `outbound_type`,`ship_data`.`check_table`.`check_type` AS `check_type`,`ship_data`.`check_table`.`production_mode` AS `production_mode`,`ship_data`.`check_table`.`sku_qty` AS `sku_qty`,`ship_data`.`check_table`.`total_qty` AS `total_qty`,`ship_data`.`check_table`.`uncheck_qty` AS `uncheck_qty`,`ship_data`.`check_table`.`container_no` AS `container_no`,`ship_data`.`check_table`.`production_wave_no` AS `production_wave_no`,`ship_data`.`check_table`.`carriage_no` AS `carriage_no`,`ship_data`.`check_table`.`realcarriage_no` AS `realcarriage_no`,`ship_data`.`check_table`.`case_no` AS `case_no`,`ship_data`.`check_table`.`rebinwall_no` AS `rebinwall_no`,`ship_data`.`check_table`.`locate_sum_qty` AS `locate_sum_qty`,`ship_data`.`check_table`.`check_differ_qty_small` AS `check_differ_qty_small`,`ship_data`.`check_table`.`supplier_code` AS `supplier_code`,`ship_data`.`check_table`.`supplier_name` AS `supplier_name`,`ship_data`.`check_table`.`broke_type` AS `broke_type`,`ship_data`.`check_table`.`outbound_level` AS `outbound_level`,`ship_data`.`check_table`.`outbound_time` AS `outbound_time`,`ship_data`.`check_table`.`sort_entry` AS `sort_entry`,`ship_data`.`check_table`.`end_time` AS `end_time`,`ship_data`.`check_table`.`end_time_attr` AS `end_time_attr`,`ship_data`.`check_table`.`send_address` AS `send_address`,`ship_data`.`check_table`.`site_no` AS `site_no`,`ship_data`.`check_table`.`site_name` AS `site_name`,`ship_data`.`check_table`.`sort_slot_no` AS `sort_slot_no`,`ship_data`.`check_table`.`valueadd_flag` AS `valueadd_flag`,`ship_data`.`check_table`.`package_qty` AS `package_qty`,`ship_data`.`check_table`.`send_type` AS `send_type`,`ship_data`.`check_table`.`resource` AS `resource`,`ship_data`.`check_table`.`platform_no` AS `platform_no`,`ship_data`.`check_table`.`pack_table_no` AS `pack_table_no`,`ship_data`.`check_table`.`total_weight` AS `total_weight`,`ship_data`.`check_table`.`total_volume` AS `total_volume`,`ship_data`.`check_table`.`status` AS `status`,`ship_data`.`check_table`.`status_lock` AS `status_lock`,`ship_data`.`check_table`.`cancel_order_status` AS `cancel_order_status`,`ship_data`.`check_table`.`is_shortage` AS `is_shortage`,`ship_data`.`check_table`.`check_num` AS `check_num`,`ship_data`.`check_table`.`multiple_check` AS `multiple_check`,`ship_data`.`check_table`.`org_no` AS `org_no`,`ship_data`.`check_table`.`distribute_no` AS `distribute_no`,`ship_data`.`check_table`.`warehouse_no` AS `warehouse_no`,`ship_data`.`check_table`.`create_user` AS `create_user`,`ship_data`.`check_table`.`create_time` AS `create_time`,`ship_data`.`check_table`.`update_user` AS `update_user`,`ship_data`.`check_table`.`update_time` AS `update_time`,`ship_data`.`check_table`.`yn` AS `yn`,`ship_data`.`check_table`.`OWNER_NO` AS `OWNER_NO`,`ship_data`.`check_table`.`OWNER_NAME` AS `OWNER_NAME`,`ship_data`.`check_table`.`batch_no` AS `batch_no`,`ship_data`.`check_table`.`check_business_tag` AS `check_business_tag`,`ship_data`.`check_table`.`group_no` AS `group_no`,`ship_data`.`check_table`.`TRIAL_PRODUCT_FLAG` AS `TRIAL_PRODUCT_FLAG`,`ship_data`.`check_table`.`CHECK_MODE` AS `CHECK_MODE`,`ship_data`.`check_table`.`check_differ_qty_total` AS `check_differ_qty_total`,`ship_data`.`check_table`.`check_differ_qty_medium` AS `check_differ_qty_medium`,`ship_data`.`check_table`.`picking_finished` AS `picking_finished`,`ship_data`.`check_table`.`cell_no` AS `cell_no`,`ship_data`.`check_table`.`rebin_no` AS `rebin_no`,`ship_data`.`check_table`.`status_picking` AS `status_picking`,`ship_data`.`check_table`.`status_picking_small` AS `status_picking_small`,`ship_data`.`check_table`.`status_picking_medium` AS `status_picking_medium`,`ship_data`.`check_table`.`status_small` AS `status_small`,`ship_data`.`check_table`.`status_medium` AS `status_medium`,`ship_data`.`check_table`.`picking_time` AS `picking_time`,`ship_data`.`check_table`.`isv_outstore_no` AS `isv_outstore_no`,`ship_data`.`check_table`.`pick_type` AS `pick_type`,`ship_data`.`check_table`.`sf_ship_no` AS `sf_ship_no`,`ship_data`.`check_table`.`isCollectDeliveryInfo` AS `isCollectDeliveryInfo`,`ship_data`.`check_table`.`expect_package_qty` AS `expect_package_qty`,`ship_data`.`check_table`.`print_shopping_flag` AS `print_shopping_flag`,`ship_data`.`check_table`.`product_mode_flag` AS `product_mode_flag`,`ship_data`.`check_table`.`schedulebill_code` AS `schedulebill_code`,`ship_data`.`check_table`.`uppershelf_time` AS `uppershelf_time`,`ship_data`.`check_table`.`mixedorder_type` AS `mixedorder_type`,`ship_data`.`check_table`.`child_order_flag` AS `child_order_flag`,`ship_data`.`check_table`.`inbound_no` AS `inbound_no`,`ship_data`.`check_table`.`production_order_no` AS `production_order_no`,`ship_data`.`check_table`.`check_user` AS `check_user`,`ship_data`.`check_table`.`check_finish_time` AS `check_finish_time`,`ship_data`.`check_table`.`check_style` AS `check_style` from `ship_data`.`check_table` where ((`ship_data`.`check_table`.`outbound_no` = 'ESL48400163536608') and (`ship_data`.`check_table`.`yn` = 0) and (`ship_data`.`check_table`.`update_user` = 'jilei18'))"
          }
        ]
      }
    },
    {
      "join_optimization": { #optimize階段
        "select#": 1,
        "steps": [
          {
            "condition_processing": {#處理搜索條件
              "condition": "WHERE",
              "original_condition": "((`ship_data`.`check_table`.`outbound_no` = 'ESL48400163536608') and (`ship_data`.`check_table`.`yn` = 0) and (`ship_data`.`check_table`.`update_user` = 'jilei18'))",
              "steps": [
                {
                  "transformation": "equality_propagation",#處理等值轉換
                  "resulting_condition": "((`ship_data`.`check_table`.`outbound_no` = 'ESL48400163536608') and (`ship_data`.`check_table`.`update_user` = 'jilei18') and multiple equal(0, `ship_data`.`check_table`.`yn`))"
                },
                {
                  "transformation": "constant_propagation",#常量傳遞轉換
                  "resulting_condition": "((`ship_data`.`check_table`.`outbound_no` = 'ESL48400163536608') and (`ship_data`.`check_table`.`update_user` = 'jilei18') and multiple equal(0, `ship_data`.`check_table`.`yn`))"
                },
                {
                  "transformation": "trivial_condition_removal",#去除沒用的條件
                  "resulting_condition": "((`ship_data`.`check_table`.`outbound_no` = 'ESL48400163536608') and (`ship_data`.`check_table`.`update_user` = 'jilei18') and multiple equal(0, `ship_data`.`check_table`.`yn`))"
                }
              ]
            }
          },
          {
            "substitute_generated_columns": {#去除虛擬生成的列
            }
          },
          {
            "table_dependencies": [#表的依賴信息
              {
                "table": "`ship_data`.`check_table`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [#列出所有可用的ref類型的索引
              {
                "table": "`ship_data`.`check_table`",
                "field": "outbound_no",
                "equals": "'ESL48400163536608'",
                "null_rejecting": false
              }
            ]
          },
          {
            "rows_estimation": [#預估不同單表訪問方法的訪問成本
              {
                "table": "`ship_data`.`check_table`",
                "range_analysis": {
                  "table_scan": {#全表掃描的行數及成本
                    "rows": 79745,
                    "cost": 19127
                  },
                  "potential_range_indexes": [#分析可能使用的索引,此處就是執行計劃中的possiable_keys
                    {
                      "index": "PRIMARY",#主鍵不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "UK_batch_production",#UK_batch_production索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_update_time",#idx_update_time索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "IDX_status",#IDX_status索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_case_no",#idx_case_no索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_outbound_time",#idx_outbound_time索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_outboundno",#idx_outboundno索引可用
                      "usable": true,
                      "key_parts": [
                        "outbound_no",
                        "m_id"
                      ]
                    },
                    {
                      "index": "idx_wave_no",#idx_wave_no索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_cancel_order_status",#idx_cancel_order_status索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_production_wave_no",#idx_production_wave_no索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_schedulebillcode_uppershelftime",#idx_schedulebillcode_uppershelftime索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_production_orderno",#idx_production_orderno索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_end_time_attr",#idx_end_time_attr索引不可用
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ],
                  "setup_range_conditions": [
                  ],
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  },
                  "analyzing_range_alternatives": {#分析可能使用的索引的成本
                    "range_scan_alternatives": [
                      {
                        "index": "idx_outboundno",#使用idx_outboundno索引的成本
                        "ranges": [
                          "ESL48400163536608 <= outbound_no <= ESL48400163536608"
                        ],
                        "index_dives_for_eq_ranges": true,#是否使用index_dives
                        "rowid_ordered": true,#使用該索引獲取的記錄是否按照主鍵排序
                        "using_mrr": false,#是否使用mrr
                        "index_only": false,#是否是覆蓋索引
                        "rows": 1,#使用該索引獲取的記錄條數
                        "cost": 2.21,#使用該索引花費的成本
                        "chosen": true#是否選擇該索引
                        "cause": "cost"#該欄位為作者添加,當有索引未被使用時會標記未被使用的原因,cost為成本不合理未被選用
                      }
                    ],
                    "analyzing_roworder_intersect": {#分析使用索引合併的成本
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    }
                  },
                  "chosen_range_access_summary": {#對於上述單表查詢check_table最優的方法
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_outboundno",
                      "rows": 1,
                      "ranges": [
                        "ESL48400163536608 <= outbound_no <= ESL48400163536608"
                      ]
                    },
                    "rows_for_plan": 1,
                    "cost_for_plan": 2.21,
                    "chosen": true
                  }
                }
              }
            ]
          },
          {
            "considered_execution_plans": [#分析各種可能的執行計劃
              {
                "plan_prefix": [
                ],
                "table": "`ship_data`.`check_table`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "ref",
                      "index": "idx_outboundno",
                      "rows": 1,
                      "cost": 1.2,
                      "chosen": true
                    },
                    {
                      "access_type": "range",
                      "range_details": {
                        "used_index": "idx_outboundno"
                      },
                      "chosen": false,
                      "cause": "heuristic_index_cheaper"
                    }
                  ]
                },
                "condition_filtering_pct": 5,#下麵的數據來自官網示例,作者示例中超出長度的文本無法獲取到
                "rows_for_plan": 0.05,
                                        "cost_for_plan": 8.55,
                                        "chosen": true
                                    }
                                ] /* rest_of_plan */
                            }
                        ] /* considered_execution_plans */
                    },
                    {
                        "attaching_conditions_to_tables": {#嘗試給查詢添加一些其他的查詢條件
                            "original_condition": "((`alias2`.`pk` = `alias1`.`col_int_key`) and (0 <> `alias1`.`pk`))",
                            "attached_conditions_computation": [] /* attached_conditions_computation */,
                            "attached_conditions_summary": [
                                {
                                    "table": "`t1` `alias1`",
                                    "attached": "((0 <> `alias1`.`pk`) and (`alias1`.`col_int_key` is not null))"
                                },
                                {
                                    "table": "`t2` `alias2`",
                                    "attached": "(`alias2`.`pk` = `alias1`.`col_int_key`)"
                                }
                            ] /* attached_conditions_summary */
                        } /* attaching_conditions_to_tables */
                    },
                    {
                        "optimizing_distinct_group_by_order_by": {
                            "simplifying_order_by": {
                                "original_clause": "`alias1`.`col_int_key`,`alias2`.`pk`",
                                "items": [
                                    {
                                        "item": "`alias1`.`col_int_key`"
                                    },
                                    {
                                        "item": "`alias2`.`pk`",
                                        "eq_ref_to_preceding_items": true
                                    }
                                ] /* items */,
                                "resulting_clause_is_simple": true,
                                "resulting_clause": "`alias1`.`col_int_key`"
                            } /* simplifying_order_by */,
                            "simplifying_group_by": {
                                "original_clause": "`field2`",
                                "items": [
                                    {
                                        "item": "`alias2`.`pk`"
                                    }
                                ] /* items */,
                                "resulting_clause_is_simple": false,
                                "resulting_clause": "`field2`"
                            } /* simplifying_group_by */
                        } /* optimizing_distinct_group_by_order_by */
                    },
                    {
                        "finalizing_table_conditions": [
                            {
                                "table": "`t1` `alias1`",
                                "original_table_condition": "((0 <> `alias1`.`pk`) and (`alias1`.`col_int_key` is not null))",
                                "final_table_condition   ": "((0 <> `alias1`.`pk`) and (`alias1`.`col_int_key` is not null))"
                            },
                            {
                                "table": "`t2` `alias2`",
                                "original_table_condition": "(`alias2`.`pk` = `alias1`.`col_int_key`)",
                                "final_table_condition   ": null
                            }
                        ] /* finalizing_table_conditions */
                    },
                    {
                        "refine_plan": [#再稍加改進執行計劃
                            {
                                "table": "`t1` `alias1`"
                            },
                            {
                                "table": "`t2` `alias2`"
                            }
                        ] /* refine_plan */
                    },
                    {
                        "considering_tmp_tables": [
                            {
                                "adding_tmp_table_in_plan_at_position": 2,
                                "write_method": "continuously_update_group_row"
                            },
                            {
                                "adding_sort_to_table": ""
                            } /* filesort */
                        ] /* considering_tmp_tables */
                    }
                ] /* steps */
            } /* join_optimization */
        },
        {
            "join_execution": {#execute階段
                "select#": 1,
                "steps": [
                    {
                        "temp_table_aggregate": {
                            "select#": 1,
                            "steps": [
                                {
                                    "creating_tmp_table": {
                                        "tmp_table_info": {
                                            "in_plan_at_position": 2,
                                            "columns": 3,
                                            "row_length": 18,
                                            "key_length": 4,
                                            "unique_constraint": false,
                                            "makes_grouped_rows": true,
                                            "cannot_insert_duplicates": false,
                                            "location": "TempTable"
                                        } /* tmp_table_info */
                                    } /* creating_tmp_table */
                                }
                            ] /* steps */
                        } /* temp_table_aggregate */
                    },
                    {
                        "sorting_table": "<temporary>",
                        "filesort_information": [
                            {
                                "direction": "asc",
                                "expression": "`alias1`.`col_int_key`"
                            }
                        ] /* filesort_information */,
                        "filesort_priority_queue_optimization": {
                            "usable": false,
                            "cause": "not applicable (no LIMIT)"
                        } /* filesort_priority_queue_optimization */,
                        "filesort_execution": [] /* filesort_execution */,
                        "filesort_summary": {
                            "memory_available": 262144,
                            "key_size": 9,
                            "row_size": 26,
                            "max_rows_per_buffer": 7710,
                            "num_rows_estimate": 18446744073709551615,
                            "num_rows_found": 8,
                            "num_initial_chunks_spilled_to_disk": 0,
                            "peak_memory_used": 32840,
                            "sort_algorithm": "std::sort",
                            "unpacked_addon_fields": "skip_heuristic",
                            "sort_mode": "<fixed_sort_key, additional_fields>"
                        } /* filesort_summary */
                    }
                ] /* steps */
            } /* join_execution */
        }
    ] /* steps */
}

4.總結

上述內容大致分為三個階段:prepare階段、optimize階段、execute階段,MySQL中基於成本的優化主要在optimize階段,在單表查詢時會主要關註optimize階段的rows_estimation過程,這個rows_estimation過程分析了多種執行方案的成本耗費,在多表連接查詢的時候,我們更多關註considered_execution_plans過程,不過總而言之查詢優化器最終會選擇成本最低的方案來作為最終的執行計劃,即我們使用EXPLAIN語句時顯示出的方案。


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

-Advertisement-
Play Games
更多相關文章
  • 在一些字典綁定中,往往為了方便展示詳細數據,需要把一些結構樹展現在樹列表TreeList控制項中或者下拉列表的樹形控制項TreeListLookUpEdit控制項中,為了快速的處理數據的綁定操作,比較每次使用涉及太多細節的操作,我們可以把相關的數據綁定操作,放在一些輔助類的擴展函數中進行處理,這樣可以更方... ...
  • C#泛型中new和where是重要的關鍵字,它們都可以用於約束泛型類型參數的限制;它們都用於提高代碼的安全性和可用性,它們的作用在很大程度上提高了代碼的可讀性和可維護性。在這篇文章中,我們將一起瞭解泛型中的new和where,以及它們之間的區別。 1. new關鍵字 在C#泛型中,new關鍵字被用於 ...
  • 本文演示Sitecore XP Single(XP0)在Azure上的一鍵部署,即“30分鐘生成Sitecore演示環境”的一環。 關於XP(即Sitecore Experience Platform) roles的相關介紹移步 XP Single配置主要用來開發和測試: Four Sitecore ...
  • 一、前言 本篇開始對STM32的GPIO在實際開發設計中的使用配置和技巧進行探討,可以先去回顧下之前介紹的GPIO的相關理論基礎知識包括基本結構,工作模式和寄存器原理。 瞭解過STM32的GPIO相關的理論知識,這樣在應用GPIO開發過程中,能更好的理解GPIO的特點,應用起來會更加的得心應手。 後 ...
  • Linux查看各用戶硬碟占用大小 在Linux中,如果要統計各用戶占用硬碟的大小,可以執行如下的命令 du -sh /home/* 這條命令會以K、M、G等單位輸出 /home 下各用戶目錄占用硬碟的總大小,例如下麵這樣: [root@localhost ~]# du -sh /home/* 24K ...
  • @(Linux的文本編輯器) 前言 上一篇中已經預告,我們這篇主要說Linux中vi/vim 編輯器。它是我們使用Linux系統不可缺少的工具,學會了,你就可以在Linux世界里暢通無阻,學廢了,常用操作你也會了,也是夠用了,O(∩_∩)O 簡介 vi是Linux系統下標準編輯器,就相當於Windo ...
  • squid介紹 官網地址:http://www.squid-cache.org/ Squid cache(簡稱為 Squid)是一個流行的自由軟體(GNU 通用公共許可證)的代理伺服器和 Web 緩存伺服器。Squid 有廣泛的用途,從作為網頁伺服器的前置 cache 伺服器緩存相關請求來提高 We ...
  • -- 創建表 drop table if exists emp; create table emp( empno int, ename varchar(50), job varchar(50), mgr int, hiredate date, sal decimal(7,2), comm decim ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...