[20221128]再談防水牆(視圖訪問性能問題).txt

来源:https://www.cnblogs.com/lfree/archive/2022/12/02/16943486.html
-Advertisement-
Play Games

同一個數據分析的需求,不同人的SQL代碼效率上會差別很大!本文給大家梳理集中效率優化方法,這也是數據崗面試的高頻問題哦!快學起來~ ...


[20221128]再談防水牆(視圖訪問性能問題).txt

1.環境:
SYS> @ ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

2.問題分析:
--//上個星期看了生產系統awr報表,發現一些問題.原來防水牆不斷調用執行如下:
begin :con := "TASSETACL"."QUERYACL"(:sn, :on); end;
--//該語句已經消失,我問了同事,據說升級過該產品,當時awr的記錄如下:
SQL ordered by Executions

    %CPU - CPU Time as a percentage of Elapsed Time
    %IO - User I/O Time as a percentage of Elapsed Time
    Total Executions: 23,199,582
    Captured SQL account for 34.2% of Total

Executions      Rows Processed  Rows per Exec   Elapsed Time (s)%CPU    %IO   SQL Id          SQL Module      SQL Text
6,522,522       6,521,177       1.00            1,660.15        99.4    0     190q1sz3ywrd7   xxxxxx.eee      begin :con := "TASSETACL".QUE...
2,228,287       2,228,115       1.00            107.98          99.5    0     g7ytdh9mxt1s0   xxxxxx.eee      select count ( :"SYS_B_0" ) fr...

--//而現在變成瞭如下:
SQL ordered by Elapsed Time

    Resources reported for PL/SQL code includes the resources used by all SQL statements called by the code.
    為PL/SQL代碼報告的資源包括該代碼調用的所有SQL語句所使用的資源。
    % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100
    %Total - Elapsed Time as a percentage of Total DB time
    %CPU - CPU Time as a percentage of Elapsed Time
    %IO - User I/O Time as a percentage of Elapsed Time
    Captured SQL account for 65.1% of Total DB Time (s): 33,342
    Captured PL/SQL account for 41.7% of Total DB Time (s): 33,342

Elapsed Time (s)  Executions   Elapsed Time per Exec (s)  %Total  %CPU   %IO  SQL Id         SQL Module                                 SQL Text
5,156.39          33,682       0.15                       15.47   98.35  0.01 3pw59r6rkw9gb  [email protected] (TNS V1-  declare PRIVS_ERROR exception;...
5,153.22          33,683       0.15                       15.46   98.34  0.01 0xwxau19hznj8  [email protected] (TNS V1-  begin dbagent.try_login(); end...
5,089.67          134,713      0.04                       15.26   98.34  0.00 8vmu6k690g87k  [email protected] (TNS V1-  SELECT UPPER(NVL(PROGRAM, 'nul...

--//原來的問題消失了,但是消耗的時間卻增加了,很明顯對方的產品沒有經過嚴格的測試,就給用戶使用了.
--//取出sql語句,主要便於查看並且格式化如下:
SYS> @ sql_id 3pw59r6rkw9gb
--SQL_ID = 3pw59r6rkw9gb
declare
  PRIVS_ERROR exception; --raise error,if rule exception,will trigger privs_error
  pragma exception_init(PRIVS_ERROR, -1031);
begin
  execute immediate 'begin dbagent.try_login(); end;';
exception
  when PRIVS_ERROR then
    raise;
  when others then
    rollback;
end dbagent_logon;;
--//註意後面多了1個分號,是我寫的腳本無法區分PL/SQL語句與sql語句造成的問題.

SYS> @sql_id 0xwxau19hznj8
--SQL_ID = 0xwxau19hznj8
begin dbagent.try_login(); end;;

SYS> @ sql_id 8vmu6k690g87k
--SQL_ID = 8vmu6k690g87k
SELECT UPPER (NVL (PROGRAM, 'null'))
      ,UPPER (MODULE)
      ,TYPE
      ,DECODE
       (
          NVL (INSTR (PROCESS, ':'), 0)
         ,0, NVL (PROCESS, 1234)
         ,SUBSTR (PROCESS, 1, INSTR (PROCESS, ':') - 1)
       )
      ,OSUSER
      ,MACHINE
      ,SCHEMANAME
      ,USERNAME
      ,SERVICE_NAME
      ,SID
      ,SERIAL#
  FROM SYS.V_$SESSION
 WHERE SID = SYS_CONTEXT ('userenv', 'sid');

--//134713/33682 = 3.99955.平均執行3pw59r6rkw9gb1次,執行8vmu6k690g87k 4次.
--//可以看出調用順序3pw59r6rkw9gb,0xwxau19hznj8,8vmu6k690g87k 分別執行次數的比例是1:1:4.
--//很明顯開發沒有寫好程式代碼.僅僅需要調用1次8vmu6k690g87k就ok了.
--//如果修改代碼可以提高效率4倍. 僅僅需要5156/4 = 1289秒.但是我的問題並不再這裡,細節很重要,為什麼8vmu6k690g87k的執行有點
--//慢.再仔細看sql_id='8vmu6k690g87k'每次執行需要0.04秒=40ms(估計存在四捨五入問題,因為0.04*4=0.16),有點慢,因為where條件
--//查詢使用sid,不應該存在這麼"慢"的情況.

--//開始以為都是Module=oraagent.bin執行的,後面我發現實際上幾乎全部模塊都存在相似調用,看代碼可以猜出是登陸資料庫時觸發器
--//調用執行的代碼.這時我突然想起我自己寫的登陸觸發器用於設置cursor_sharing=force也存在類似的調用v$session視圖的情況,很
--//明顯我寫的代碼調用次數應該也有33XXX次數.Elapsed Time至少應該 5089/4 = 1272秒,但是並沒有出現在awr報表中.另外我想到是
--//否因為select部分消耗cpu資源太多,我馬上否定我的猜測,因為僅僅返回1行,無論如何不應該這麼"慢".

--//當我看我寫的觸發器代碼馬上明白問題在那裡.我是分開寫的,可以參考鏈接
--// http://blog.itpub.net/267265/viewspace-2768591/ => [20210418]查詢v$視圖問題.txt
--// connor-mcdonald.com/2021/04/12/better-performance-when-querying-the-v-views

3.繼續:
$ cat a.txt
SELECT UPPER (NVL (PROGRAM, 'null'))
      ,UPPER (MODULE)
      ,TYPE
      ,DECODE
       (
          NVL (INSTR (PROCESS, ':'), 0)
         ,0, NVL (PROCESS, 1234)
         ,SUBSTR (PROCESS, 1, INSTR (PROCESS, ':') - 1)
       )
      ,OSUSER
      ,MACHINE
      ,SCHEMANAME
      ,USERNAME
      ,SERVICE_NAME
      ,SID
      ,SERIAL#
  FROM SYS.V_$SESSION
 WHERE SID = SYS_CONTEXT ('userenv', 'sid');

--//查看起對應的執行計劃:
SYS> @ sl all
alter session set statistics_level = all;
Session altered.

SYS> @ a.txt
SYS> @ dpc '' '' ''
PLAN_TABLE_OUTPUT
---------------------------
Plan hash value: 2422122865
---------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows |   A-Time   |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |                 |      1 |        |       |     1 (100)|      1 |00:00:00.02 |       |       |          |
|   1 |  MERGE JOIN CARTESIAN     |                 |      1 |      1 |    62 |     0   (0)|      1 |00:00:00.02 |       |       |          |
|   2 |   NESTED LOOPS            |                 |      1 |      1 |    12 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|*  3 |    FIXED TABLE FULL       | X$KSLWT         |      1 |      1 |     8 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|*  4 |    FIXED TABLE FIXED INDEX| X$KSLED (ind:2) |      1 |      1 |     4 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|   5 |   BUFFER SORT             |                 |      1 |      1 |    50 |     0   (0)|      1 |00:00:00.02 |  2048 |  2048 | 2048  (0)|
|*  6 |    FIXED TABLE FULL       | X$KSUSE         |      1 |      1 |    50 |     0   (0)|      1 |00:00:00.02 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$88122447
   3 - SEL$88122447 / W@SEL$4
   4 - SEL$88122447 / E@SEL$4
   6 - SEL$88122447 / S@SEL$4
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("W"."KSLWTSID"=TO_NUMBER(SYS_CONTEXT('userenv','sid')))
   4 - filter("W"."KSLWTEVT"="E"."INDX")
   6 - filter((BITAND("S"."KSSPAFLG",1)<>0 AND BITAND("S"."KSUSEFLG",1)<>0 AND "S"."INDX"=TO_NUMBER(SYS_CONTEXT('userenv','sid'))
              AND "S"."INST_ID"=USERENV('INSTANCE')))
--//你可以發現ID=3,全表掃描X$KSLWT,而過濾條件是 filter("W"."KSLWTSID"=TO_NUMBER(SYS_CONTEXT('userenv','sid'))),也就是無法把
--//SYS_CONTEXT ('userenv', 'sid')當作常量處理.
--//而生產庫X$KSLWT 記錄的數量不是一般測試環境的數量.我的測試環境僅僅返回24條.而生產系統返回很多.
SYS> select count(*) from X$KSLWT;
  COUNT(*)
----------
      8793
--//訪問X$KSUSE也是出現類似的情況.

--//解決很簡單,分開寫:
--// Get user SID information
SELECT SYS_CONTEXT('userenv', 'sid')   INTO v_sid  FROM dual;

--// Get Program executable,OSUSER Details,Machine Details for this session
SELECT UPPER(NVL(PROGRAM, 'NULL')),
       UPPER(MODULE),
       DECODE(NVL(INSTR(PROCESS, ':'), 0), 0, NVL(PROCESS, 1234), SUBSTR(PROCESS, 1, INSTR(PROCESS, ':') - 1))
       TYPE, OSUSER, MACHINE, SCHEMANAME, USERNAME, SERVICE_NAME, SID, SERIAL#
  FROM SYS.V_$SESSION
  where sid = v_sid;

SYS> SELECT SYS_CONTEXT('userenv', 'sid')    FROM dual;
SYS_CONTEXT('USERENV','SID')
----------------------------
17017

$ cat a.txt
SELECT UPPER (NVL (PROGRAM, 'null'))
      ,UPPER (MODULE)
      ,TYPE
      ,DECODE
       (
          NVL (INSTR (PROCESS, ':'), 0)
         ,0, NVL (PROCESS, 1234)
         ,SUBSTR (PROCESS, 1, INSTR (PROCESS, ':') - 1)
       )
      ,OSUSER
      ,MACHINE
      ,SCHEMANAME
      ,USERNAME
      ,SERVICE_NAME
      ,SID
      ,SERIAL#
  FROM SYS.V_$SESSION
 WHERE
SID= 17017
--SID = SYS_CONTEXT ('userenv', 'sid')
;

SYS> @a.txt
..

SYS> @ dpc '' '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  gxdr0gq6nyums, child number 0
-------------------------------------
Plan hash value: 589956979
----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows |   A-Time   |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                 |      1 |        |       |     1 (100)|      1 |00:00:00.01 |       |       |          |
|   1 |  NESTED LOOPS              |                 |      1 |      1 |    62 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|   2 |   MERGE JOIN CARTESIAN     |                 |      1 |      1 |    58 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|*  3 |    FIXED TABLE FIXED INDEX | X$KSUSE (ind:1) |      1 |      1 |    50 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|   4 |    BUFFER SORT             |                 |      1 |      1 |     8 |     0   (0)|      1 |00:00:00.01 |  2048 |  2048 | 2048  (0)|
|*  5 |     FIXED TABLE FIXED INDEX| X$KSLWT (ind:1) |      1 |      1 |     8 |     0   (0)|      1 |00:00:00.01 |       |       |          |
|*  6 |   FIXED TABLE FIXED INDEX  | X$KSLED (ind:2) |      1 |      1 |     4 |     0   (0)|      1 |00:00:00.01 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$88122447
   3 - SEL$88122447 / S@SEL$4
   5 - SEL$88122447 / W@SEL$4
   6 - SEL$88122447 / E@SEL$4
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(("S"."INDX"=17017 AND BITAND("S"."KSSPAFLG",1)<>0 AND BITAND("S"."KSUSEFLG",1)<>0 AND
              "S"."INST_ID"=USERENV('INSTANCE')))
   5 - filter("W"."KSLWTSID"=17017)
   6 - filter("W"."KSLWTEVT"="E"."INDX")

--//connor-mcdonald.com 鏈接給出了另外的寫法,使用with+materialize提示:
$ cat b.txt
with mysid as ( select /*+ materialize */ userenv('SID') n from dual )
SELECT UPPER(NVL(PROGRAM, 'NULL')),
       UPPER(MODULE),
       DECODE(NVL(INSTR(PROCESS, ':'), 0), 0, NVL(PROCESS, 1234), SUBSTR(PROCESS, 1, INSTR(PROCESS, ':') - 1))
       TYPE, OSUSER, MACHINE, SCHEMANAME, USERNAME, SERVICE_NAME, SID, SERIAL#
  FROM SYS.V_$SESSION,mysid
 WHERE SID = mysid.n;

SYS> @ b.txt
..

Plan hash value: 2230424401
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                             |      1 |        |       |     4 (100)|          |      1 |00:00:00.03 |      15 |      1 |      1 |       |       |          |
|   1 |  TEMP TABLE TRANSFORMATION     |                             |      1 |        |       |            |          |      1 |00:00:00.03 |      15 |      1 |      1 |       |       |          |
|   2 |   LOAD AS SELECT               |                             |      1 |        |       |            |          |      0 |00:00:00.02 |       4 |      0 |      1 |   270K|   270K|  270K (0)|
|   3 |    FAST DUAL                   |                             |      1 |      1 |       |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       0 |      0 |      0 |       |       |          |
|   4 |   NESTED LOOPS                 |                             |      1 |      1 |    75 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       5 |      1 |      0 |       |       |          |
|   5 |    NESTED LOOPS                |                             |      1 |      1 |    71 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       5 |      1 |      0 |       |       |          |
|   6 |     NESTED LOOPS               |                             |      1 |      1 |    63 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       5 |      1 |      0 |       |       |          |
|   7 |      VIEW                      |                             |      1 |      1 |    13 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       5 |      1 |      0 |       |       |          |
|   8 |       TABLE ACCESS STORAGE FULL| SYS_TEMP_0FD9D6D71_CF54F429 |      1 |      1 |    13 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       5 |      1 |      0 |  1025K|  1025K|          |
|*  9 |      FIXED TABLE FIXED INDEX   | X$KSUSE (ind:1)             |      1 |      1 |    50 |     0   (0)|          |      1 |00:00:00.01 |       0 |      0 |      0 |       |       |          |
|* 10 |     FIXED TABLE FIXED INDEX    | X$KSLWT (ind:1)             |      1 |      1 |     8 |     0   (0)|          |      1 |00:00:00.01 |       0 |      0 |      0 |       |       |          |
|* 11 |    FIXED TABLE FIXED INDEX     | X$KSLED (ind:2)             |      1 |      1 |     4 |     0   (0)|          |      1 |00:00:00.01 |       0 |      0 |      0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$71D7A081
   2 - SEL$1
   3 - SEL$1        / DUAL@SEL$1
   7 - SEL$D67CB2D2 / MYSID@SEL$2
   8 - SEL$D67CB2D2 / T1@SEL$D67CB2D2
   9 - SEL$71D7A081 / S@SEL$5
  10 - SEL$71D7A081 / W@SEL$5
  11 - SEL$71D7A081 / E@SEL$5
Predicate Information (identified by operation id):
---------------------------------------------------
   9 - filter((BITAND("S"."KSSPAFLG",1)<>0 AND BITAND("S"."KSUSEFLG",1)<>0 AND "S"."INST_ID"=USERENV('INSTANCE') AND "S"."INDX"="MYSID"."N"))
  10 - filter("S"."INDX"="W"."KSLWTSID")
  11 - filter("W"."KSLWTEVT"="E"."INDX")

4.性能對比:
--//我在toad下測試,多次執行觀察
--//調用b.txt 大約需要2Xms.
--//調用a.txt 大約需要5Xms.
--//有時候兩者差異不大,感覺這樣比較不行,沒有考慮網路的往返.另外寫一篇測試該語句性能的blog.
--//註:我後面測試with+materialize要產生redo日誌,不建議在生產系統應用這樣的寫法,主要原因是執行頻率太高了,累積起來redo很大!!

5.為什麼調用1次0xwxau19hznj8,執行4次8vmu6k690g87k.
--//我看了一下源代碼,源代碼這次沒有加密.
--//通過過程collect_app_info調用sql_id=8vmu6k690g87k
--//而try_login代碼通過4個函數分別取得對應值

--get login app name
function get_app_name return varchar2 is
begin
  collect_app_info;
  return l_appname;
end;
--get login app module name
function get_app_module_name return varchar2 is
begin
  collect_app_info;
  return l_module;
end;

--get login app type
function get_app_type return varchar2 is
begin
  collect_app_info;
  return l_type;
end;

--get app process number
function get_app_process return number is
begin
  collect_app_info;
  return l_process;
end;
--//這樣就很好解析為什麼調用1次執行4次sql_id=8vmu6k690g87k.而實際上
  procedure collect_app_info is
  begin
    if not app_info_collect_status then
      select upper(nvl(program, 'null')),
             upper(module),
             type,
             decode(nvl(instr(process, ':'), 0),
                    0,
                    nvl(process, 1234),
                    substr(process, 1, instr(process, ':') - 1)),
             osuser,
             machine,
             SCHEMANAME,
             USERNAME,
             SERVICE_NAME,
             sid,
             serial#
        into l_appname,
             l_module,
             l_type,
             l_process,
             l_osuser,
             l_machine,
             l_SCHEMANAME,
             l_username,
             l_service_name,
             l_sid,
             l_serial#
        from sys.v_$session
       where sid = sys_context('userenv', 'sid');
    end if;

  end;

--//已經賦值給對應變數,根本不需要再通過什麼函數返回對應值.直接使用對應變數應該可以,當然我沒有測試.
--//最簡單修改:
  procedure collect_app_info is
  begin
    if not app_info_collect_status then
      select userenv('SID') into l_sid from dual;
      select upper(nvl(program, 'null')),
             upper(module),
             type,
             decode(nvl(instr(process, ':'), 0),
                    0,
                    nvl(process, 1234),
                    substr(process, 1, instr(process, ':') - 1)),
             osuser,
             machine,
             SCHEMANAME,
             USERNAME,
             SERVICE_NAME,
             sid,
             serial#
        into l_appname,
             l_module,
             l_type,
             l_process,
             l_osuser,
             l_machine,
             l_SCHEMANAME,
             l_username,
             l_service_name,
             l_sid,
             l_serial#
        from sys.v_$session
       where sid = l_sid;
    end if;

  end;
--//我的感覺可能分開寫效率更高!!因為使用with+materialize會生成一個臨時表,會產生日誌,我還給測試看看.

6.總結:
--//很明顯對方缺乏蠻力測試就把產品做了升級,我曾經對乙方工程師講過類似的問題,儘量不要讓客戶先於你發現產品的問題,這樣是很
--//丟臉的事情.你內部測試怎麼犯錯都可以,客戶是看不見的,一旦你犯錯,對方先發現,對方會........

--//實際上只要大量用戶連接資料庫,該語句的問題才明顯的暴露出來.
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux 基礎-新手必備命令 概述 常見執行 Linux 命令的格式是這樣的: 命令名稱 [命令參數] [命令對象] 註意,命令名稱、命令參數、命令對象之間請用空格鍵分隔。 命令對象一般是指要處理的文件、目錄、用戶等資源,而命令參數可以用長格式(完整的選項名稱),也可以用短格式(單個字母的縮寫), ...
  • 1 hadoop-最全最完整的保姆級的java大數據學習資料 大數據技術解決的是什麼問題? 大數據技術解決的主要是海量數據的存儲和計算。 Hadoop的廣義和狹義之分 狹義的Hadoop:指的是一個框架,Hadoop是由三部分組成:HDFS:分散式文件系統--> 存儲; MapReduce:分散式離 ...
  • 學習中的思考 在 mysql 學習和使用中,我遇到了不少的難題,我覺得我應該形成一套邏輯思考體系,可以讓我在初識 mysql 的過程中加入理性思考,從一開始就探求原理,瞭解所學內容的核心和關鍵點,做到一葉知秋而不是只見樹木不見森林。 mysql 幾種數據類型的底層是如何存儲的,不同的 sql 語句對 ...
  • 緣起 StoneDB 在列式存儲引擎 Tianmu 的加持下,在大多數場景下相對 MySQL 都會有大幅性能提升。當然,這是需要工程師不斷優化代碼才能做到的,而且,性能好也需要通過基準測試才有說服力,所以我們也會針對 TPC-H 的測試語句進行測試排查,爭取不斷提升 StoneDB 的性能。本文主要 ...
  • 近年來大家可能都有這樣一種感受:與編程語言市場不同,資料庫市場的競爭激烈異常——一線的在停滯甚至下墜,二線的正在反超。有種種跡象表明:MySQL 這個流行榜上的榜一大哥,正在逐漸淡出專業開發者的視野。再見 MySQL,可能不再只是一個嘩眾取寵的梗了! ...
  • 摘要:為實現不同的功能,GaussDB(DWS)提供了不同的數據對象類型,包括索引、行存表、列存表及其輔助表等。這些數據對象在特定的條件下實現不同的功能,為資料庫的快速高效提供了保證,本文對部分數據對象進行介紹。 本文分享自華為雲社區《GaussDB(DWS)之數據對象及相互關係總結》,作者:我的橘 ...
  • 簡述 本文主要介紹如何使用 CloudCanal 構建一條 MySQL 到 Greenplum / PostgreSQL 的數據同步鏈路。 支持版本 源端 MySQL 支持的版本為:5.6、5.7、8.X 對端 PostgreSQL 支持的版本為:8.4、9.0、9.1、9.2、9.3 9.4、9. ...
  • 1.JDBC概述 1.1 基本概念 JDBC(Java Database Connectivity)就是Java資料庫連接,是一種用於執行SQL語句的Java技術,提供了訪問多種關係資料庫的統一方式,主要藉助Java語言編寫的類和介面。 1.2 JDBC 原理 JDBC是由SUN公司定義的一套訪問數 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...