当前位置: 首页 > news >正文

达梦SQL 优化简介

目录

一、定位慢 SQL

(一)开启跟踪日志记录

1.跟踪日志记录配置

(二)通过系统视图查看

1.SQL 记录配置

2.查询方式

二、SQL分析方法

(一)执行计划

1.概述

2.查看执行计划

(二)常见操作符解读

1.NSET:结果集收集

2.PRJT:投影

3.SLCT:选择

4.AAGR:简单聚集

5.FAGR:快速聚集

6.HAGR:HASH 分组聚集

7.SAGR:流分组聚集

8.BLKUP:二次扫描 (回表)

9.CSCN:全表扫描

10.SSEK、CSEK、SSCN:索引扫描

11.NEST LOOP:嵌套循环连接

12.HASH JOIN:哈希连接

13.MERGE JOIN:归并排序连接

(三)ET 工具

1.功能的开启/关闭

(四)dbms_sqltune 工具

(五)存储过程调试

1.图形化界面工具进行调试

2.DMDBG 进行调试

三、SQL 语句优化

 (一)索引

(二)SQL 语句改写

1.优化 GROUP BY

2.用 UNION ALL 替换 UNION

3.用 EXISTS 替换 DISTINCT

4.多使用 COMMIT

 5.用WHERE子句替换HAVING子句

6.用TRUNCATE替换DELETE

7.用 EXISTS 替换 IN、用 NOT EXISTS 替换 NOT IN

8.半连接优化

9.反连接优化

(三)表设计优化

1.表类型选择

2.水平分区表

3.全局临时表

4.hint优化sql


一、定位慢 SQL

定位执行效率低的 SQL 语句是 SQL 优化的第一步。待优化的 SQL 可大致分为两类:SQL执行时间在十几秒到数十秒之间,但执行频率不高,此类 SQL 对数据库整体性能影响并不大,可以放到最后进行优化。

SQL 单独执行时间可能很快,在几百毫秒到几秒之间,但执行频率非常高,甚至达到每秒上百次,高并发下执行效率降低,很可能导致系统瘫痪,此类 SQL 是优化的首要对象。

(一)开启跟踪日志记录

跟踪日志文件是一个纯文本文件,以”dmsql_实例名_日期_时间命名.log”,默认生成在 DM 安装目录的 log 子目录下。跟踪日志内容包含系统各会话执行的 SQL 语句、参数信息、错误信息、执行时间等。跟踪日志主要用于分析错误和分析性能问题,基于跟踪日志可以对系统运行状态进行分析。

1.跟踪日志记录配置

(1)配置 dm.ini 文件,设置 SVR_LOG = 1 以启用 sqllog.ini 配置,该参数为动态参数,可通过调用数据库函数直接修改,如下所示:

SP_SET_PARA_VALUE(1,'SVR_LOG',1);

(2)配置数据文件目录下的 sqllog.ini 文件。

[dmdba@localhost DAMENG]$ cat sqllog.ini

BUF_TOTAL_SIZE  = 10240  #SQLs Log Buffer Total Size(K)(1024~1024000)

BUF_SIZE        = 1024   #SQLs Log Buffer Size(K)(50~409600)

BUF_KEEP_CNT    = 6      #SQLs Log buffer keeped count(1~100)

[SLOG_ALL]

    FILE_PATH       = ../log

    PART_STOR       = 0

    SWITCH_MODE     = 1

    SWITCH_LIMIT    = 100000

    ASYNC_FLUSH     = 0

    FILE_NUM        = 200

    ITEMS           = 0

    SQL_TRACE_MASK  = 2:3:23:24:25

    MIN_EXEC_TIME   = 0

    USER_MODE       = 0

    USERS           =

注意

为避免记录 SQL log 对服务器产生较大的影响,可以配置异步日志刷新(参数 ASYNC_FLUSH 设置为 1)。

(3)如果对 sqllog.ini 进行了修改,可通过调用以下函数即时生效,无需重启数据库,如下所示:

SP_REFRESH_SVR_LOG_CONFIG();

(二)通过系统视图查看

DM 数据库提供系统动态视图,可自动记录执行时间超过设定阈值的 SQL 语句。

1.SQL 记录配置

当 INI 参数 ENABLE_MONITOR=1、MONITOR_TIME=1 打开时,显示系统最近 1000 条执行时间超过预定值的 SQL 语句,默认预定值为 1000 毫秒。

以上两个参数可通过 SP_SET_PARA_VALUE 系统函数修改,通过 SF_GET_PARA_VALUE 系统函数查看当前值。

--修改参数值

SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);

SP_SET_PARA_VALUE(1,'MONITOR_TIME',1);

--查看参数值

select SF_GET_PARA_VALUE(1,'ENABLE_MONITOR');

select SF_GET_PARA_VALUE(1,'MONITOR_TIME');

注意

两个参数均为动态参数,可直接调用系统函数进行修改,无须重启数据库实例服务;
通过 SP_SET_PARA_VALUE 方式修改的参数值仅对当前会话以及新建会话生效,对其它已建立会话不生效。

2.查询方式

  • 查询当前正在执行的会话信息。

SELECT * FROM (SELECT 'SP_CLOSE_SESSION('||SESS_ID||');' AS CLOSE_SESSION,

       DATEDIFF(SS,LAST_SEND_TIME,SYSDATE) sql_exectime,

       TRX_ID,

       CLNT_IP,

       B.IO_WAIT_TIME AS IO_WAIT_TIME,

       SF_GET_SESSION_SQL(SESS_ID) FULLSQL,

       A.SQL_TEXT

 FROM V$SESSIONS a,V$SQL_STAT B WHERE STATE IN ('ACTIVE','WAIT')

 AND A.SESS_ID = B.SESSID

 )

SQL_TEXT 列记录的是部分 SQL 语句;FULLSQL 列存储了完整的执行 SQL 语句。

  • 查询超过执行时间阈值的 SQL 语句。

可通过查询 V$LONG_EXEC_SQLS 系统视图获取结果:

SELECT * FROM V$LONG_EXEC_SQLS;

查询结果字段详细信息介绍如下表所示:

列名

说明

SESS_ID

会话 ID,会话唯一标识

SQL_ID

语句 ID,语句唯一标识

SQL_TEXT

SQL 文本

EXEC_TIME

执行时间(毫秒)

FINISH_TIME

执行结束时间

N_RUNS

执行次数

SEQNO

编号

TRX_ID

事务号

二、SQL分析方法

(一)执行计划

1.概述

简单来说,执行计划就是一条 SQL 语句在数据库中的执行过程或访问路径的描述。SQL 语言是种功能强大且非过程性的编程语言,比如以下这条 SQL 语句:

SELECT * FROM T1, T2 WHERE T1.ID = T2.ID AND T1.ID = 6;

开发人员只关心 SQL 语句能否返回 T1 与 T2 表的关联查询结果,不需要指定该 SQL 如何执行,也就是说不关心该 SQL 是先访问 T1 表还是先访问 T2 表。对于 SQL 来说,两种访问方式就是两个执行计划,查询优化器 (CBO) 将根据代价也就是开销来选择最优的执行计划。以如下 SQL 语句执行计划为例:

SELECT * FROM SYSOBJECTS;

1   #NSET2: [0, 1282, 396]

2     #PRJT2: [0, 1282, 396]; exp_num(17), is_atom(FALSE)

3       #CSCN2: [0, 1282, 396]; SYSINDEXSYSOBJECTS(SYSOBJECTS as SYSOBJECTS)

执行计划的每行即为一个计划节点,主要包含三部分信息。

  • 第一部分 NEST2、PRJT2、CSCN2 为操作符及数据库具体执行了什么操作。
  • 第二部分的三元组为该计划节点的执行代价,具体含义为[代价,记录行数,字节数]。
  • 第三部分为操作符的补充信息。

例如:第三个计划节点表示操作符是 CSCN2(即全表扫描),代价估算是 0 ms,扫描的记录行数是 1282 行,输出字节数是 396 个。

各计划节点的执行顺序为:缩进越多的越先执行,同样缩进的上面的先执行,下面的后执行,上下的优先级高于内外。缩进最深的,最先执行;缩进深度相同的,先上后下。口诀:最右最上先执行。

#CSCN2: [1, 2, 12]; INDEX33555496(TEST)

 操作符,[代价,行数,字节数] 描述

2.查看执行计划

达梦数据库可通过两种方式查看执行计划。

方式一:通过 DM 数据库配套管理工具查看。

方式二:使用 explain 命令查看。

以下对两种查看方式进行介绍。

(1)管理工具查看执行计划

(2)在 DM 配套管理工具中,选中待查看执行计划的 SQL 语句,点击工具栏中的按钮,或使用快捷键 F9,即可查看执行计划。

(3)使用 explain 命令查看执行计划

(4)在待查看执行计划的 SQL 语句前加 explain 执行 SQL 语句即可查看预估的执行计划:

explain select * from sysobjects;

--执行计划

1   #NSET2: [1, 986, 396]

2     #PRJT2: [1, 986, 396]; exp_num(17), is_atom(FALSE)

3       #CSCN2: [1, 986, 396]; SYSINDEXSYSOBJECTS(SYSOBJECTS as SYSOBJECTS)

(5)使用 disql 命令行查真实执行计划

SQL> set autotrace traceonly

SQL> select * from sysobjects;

2348 rows got

1   #NSET2: [1, 2348->2348, 397]

2     #PRJT2: [1, 2348->2348, 397]; exp_num(17), is_atom(FALSE)

3       #CSCN2: [1, 2348->2348, 397]; SYSINDEXSYSOBJECTS(SYSOBJECTS)

Statistics-----------------------------------------------------------------

        0           data pages changed

        0           undo pages changed

        67          logical reads

        0           physical reads

        0           redo size

        364191      bytes sent to client

        155         bytes received from client

        2           roundtrips to/from client

        0           sorts (memory)

        0           sorts (disk)

        2348        rows processed

        0           io wait time(ms)

        2           exec time(ms)

重点关注 logical reads(逻辑读)和 physical reads(物理读)相应的指标值,并结合 rows processed 返回处理行数多少来分析。如果返回行数少(并且 bytes sent to client 总量不大),应尽可能减少 IO 开销,让执行计划选择正确的索引路径。

Sort(disk) 一般因排序( hash join 发生归并、order by、group by 场景)区内存不足,如果数据库服务器物理内存充足,可以适当上调排序区内存,尽量避免操作刷盘,否则会影响执行性能。

(二)常见操作符解读

下面通过几个例子来介绍一些常见操作符。准备测试表及数据如下:

DROP TABLE T1;

DROP TABLE T2;

CREATE TABLE T1(C1 INT ,C2 CHAR(1),C3 VARCHAR(10) ,C4 VARCHAR(10) );

CREATE TABLE T2(C1 INT ,C2 CHAR(1),C3 VARCHAR(10) ,C4 VARCHAR(10) );

INSERT INTO T1

SELECT LEVEL C1,CHR(65+MOD(LEVEL,57)) C2,'TEST',NULL FROM DUAL

CONNECT BY LEVEL<=10000;

INSERT INTO T2

SELECT LEVEL C1,CHR(65+MOD(LEVEL,57)) C2,'TEST',NULL  FROM DUAL

CONNECT BY LEVEL<=10000;

CREATE INDEX IDX_C1_T1 ON T1(C1);

SP_INDEX_STAT_INIT(USER,'IDX_C1_T1');

1.NSET:结果集收集

EXPLAIN SELECT * FROM T1;

1   #NSET2: [1, 10000, 156]

2     #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)

3       #CSCN2: [1, 10000, 156]; INDEX33556710(T1)

NSET 是用于结果集收集的操作符,一般是查询计划的顶层节点,优化工作中无需对该操作符过多关注,一般没有优化空间。

2.PRJT:投影

EXPLAIN SELECT * FROM T1;

1   #NSET2: [1, 10000, 156]

2     #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)

3       #CSCN2: [1, 10000, 156]; INDEX33556710(T1)

PRJT 是关系的【投影】 (project) 运算,用于选择表达式项的计算。广泛用于查询,排序,函数索引创建等。优化工作中无需对该操作符过多关注,一般没有优化空间。

3.SLCT:选择

EXPLAIN SELECT * FROM T1 WHERE C2='TEST';

1   #NSET2: [1, 250, 156]

2     #PRJT2: [1, 250, 156]; exp_num(5), is_atom(FALSE)

3       #SLCT2: [1, 250, 156]; T1.C2 = TEST

4         #CSCN2: [1, 10000, 156]; INDEX33556717(T1)

SLCT 是关系的【选择】运算,用于查询条件的过滤。可比较返回结果集与代价估算中是否接近,如相差较大可考虑收集统计信息。若该过滤条件过滤性较好,可考虑在条件列增加索引。

4.AAGR:简单聚集

EXPLAIN SELECT COUNT(*) FROM T1 WHERE C1 = 10;

1   #NSET2: [0, 1, 4]

2     #PRJT2: [0, 1, 4]; exp_num(1), is_atom(FALSE)

3       #AAGR2: [0, 1, 4]; grp_num(0), sfun_num(1)

4         #SSEK2: [0, 1, 4]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]

AAGR 用于没有 GROUP BY 的 COUNT、SUM、AGE、MAX、MIN 等聚集函数的计算。

5.FAGR:快速聚集

EXPLAIN  SELECT MAX(C1) FROM T1;

1   #NSET2: [1, 1, 0]

2     #PRJT2: [1, 1, 0]; exp_num(1), is_atom(FALSE)

3       #FAGR2: [1, 1, 0]; sfun_num(1)

FAGR 用于没有过滤条件时,从表或索引快速获取 MAX、MIN、COUNT 值。

6.HAGR:HASH 分组聚集

EXPLAIN SELECT COUNT(*) FROM T1 GROUP BY C2;

1   #NSET2: [1, 100, 48]

2     #PRJT2: [1, 100, 48]; exp_num(1), is_atom(FALSE)

3       #HAGR2: [1, 100, 48]; grp_num(1), sfun_num(1)

4         #CSCN2: [1, 10000, 48]; INDEX33556717(T1)

HAGR 用于分组列没有索引只能走全表扫描的分组聚集,该示例中 C2 列没有创建索引。

7.SAGR:流分组聚集

EXPLAIN SELECT COUNT(*) FROM T1 GROUP BY C1;

1   #NSET2: [1, 100, 4]

2     #PRJT2: [1, 100, 4]; exp_num(1), is_atom(FALSE)

3       #SAGR2: [1, 100, 4]; grp_num(1), sfun_num(1)

4         #SSCN: [1, 10000, 4]; IDX_C1_T1(T1)

SAGR 用于分组列是有序的情况下,可以使用流分组聚集,C1 列上已经创建了索引,SAGR2 性能优于 HAGR2。

8.BLKUP:二次扫描 (回表)

EXPLAIN SELECT * FROM T1 WHERE C1=10;

1   #NSET2: [0, 1, 156]

2     #PRJT2: [0, 1, 156]; exp_num(5), is_atom(FALSE)

3       #BLKUP2: [0, 1, 156]; IDX_C1_T1(T1)

4         #SSEK2: [0, 1, 156]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]

BLKUP 先使用二级索引索引定位 rowid,再根据表的主键、聚集索引、rowid 等信息获取数据行中其它列。

9.CSCN:全表扫描

EXPLAIN SELECT * FROM T1;

1   #NSET2: [1, 10000, 156]

2     #PRJT2: [1, 10000, 156]; exp_num(5), is_atom(FALSE)

3       #CSCN2: [1, 10000, 156]; INDEX33556710(T1)

CSCN2 是 CLUSTER INDEX SCAN 的缩写即通过聚集索引扫描全表,全表扫描是最简单的查询,如果没有选择谓词,或者没有索引可以利用,则系统一般只能做全表扫描。全表扫描 I/O 开销较大,在一个高并发的系统中应尽量避免全表扫描。

10.SSEK、CSEK、SSCN:索引扫描

-- 创建所需索引

CREATE CLUSTER INDEX IDX_C1_T2  ON T2(C1);

CREATE  INDEX IDX_C1_C2_T1  ON T1(C1,C2);

SSEK

EXPLAIN SELECT * FROM T1 WHERE C1=10;

1   #NSET2: [0, 1, 156]

2     #PRJT2: [0, 1, 156]; exp_num(5), is_atom(FALSE)

3       #BLKUP2: [0, 1, 156]; IDX_C1_T1(T1)

4         #SSEK2: [0, 1, 156]; scan_type(ASC), IDX_C1_T1(T1), scan_range[10,10]

SSEK2 是二级索引扫描即先扫描索引,再通过主键、聚集索引、rowid 等信息去扫描表。

CSEK

EXPLAIN SELECT * FROM T2 WHERE C1=10;

1   #NSET2: [0, 250, 156]

2     #PRJT2: [0, 250, 156]; exp_num(5), is_atom(FALSE)

3       #CSEK2: [0, 250, 156]; scan_type(ASC), IDX_C1_T2(T2), scan_range[10,10]

CSEK2 是聚集索引扫描只需要扫描索引,不需要扫描表,即无需 BLKUP 操作,如果 BLKUP 开销较大时,可考虑创建聚集索引。

SSCN

EXPLAIN SELECT C1,C2 FROM T1;

1   #NSET2: [1, 10000, 60]

2     #PRJT2: [1, 10000, 60]; exp_num(3), is_atom(FALSE)

3       #SSCN: [1, 10000, 60]; IDX_C1_C2_T1(T1)

SSCN 是索引全扫描,不需要扫描表。

11.NEST LOOP:嵌套循环连接

嵌套循环连接是最基础的连接方式,将一张表(驱动表)的每一个值与另一张表(被驱动表)的所有值拼接,形成一个大结果集,再从大结果集中过滤出满足条件的行。驱动表的行数就是循环的次数,将在很大程度上影响执行效率。

连接列是否有索引,都可以走 NEST LOOP,但没有索引,执行效率会很差,语句如下所示:

select /*+use_nl(t1,t2)*/* from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';

1   #NSET2: [17862, 24725, 296]

2     #PRJT2: [17862, 24725, 296]; exp_num(8), is_atom(FALSE)

3       #SLCT2: [17862, 24725, 296]; T1.C1 = T2.C1

4         #NEST LOOP INNER JOIN2: [17862, 24725, 296];

5           #SLCT2: [1, 250, 148]; T1.C2 = 'A'

6             #CSCN2: [1, 10000, 148]; INDEX33555594(T1)

7           #CSCN2: [1, 10000, 148]; INDEX33555595(T2)

可针对 T1 和 T2 的连接列创建索引,并收集统计信息,语句如下所示:

CREATE INDEX IDX_T1_C2  ON T1(C2);CREATE INDEX IDX_T2_C1  ON T2(C1);

DBMS_STATS.GATHER_INDEX_STATS(USER,'IDX_T1_C2');

DBMS_STATS.GATHER_INDEX_STATS(USER,'IDX_T2_C1');

再次查看执行计划可看出效率明显改善,代价有显著下降,语句如下所示:

select /*+use_nl(t1,t2)*/* from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';

1   #NSET2: [9805, 17151, 296]

2     #PRJT2: [9805, 17151, 296]; exp_num(8), is_atom(FALSE)

3       #SLCT2: [9805, 17151, 296]; T1.C1 = T2.C1

4         #NEST LOOP INNER JOIN2: [9805, 17151, 296];

5           #BLKUP2: [1, 175, 148]; IDX_T1_C2(T1)

6             #SSEK2: [1, 175, 148]; scan_type(ASC), IDX_T1_C2(T1), scan_range['A','A']

7           #CSCN2: [1, 10000, 148]; INDEX33555585(T2)

适用场景:

驱动表有很好的过滤条件

表连接条件能使用索引

结果集比较小

12.HASH JOIN:哈希连接

哈希连接是在没有索引或索引无法使用情况下大多数连接的处理方式。哈希连接使用关联列去重后结果集较小的表做成 HASH 表,另一张表的连接列在 HASH 后向 HASH 表进行匹配,这种情况下匹配速度极快,主要开销在于对连接表的全表扫描以及 HASH 运算。

select * from t1 inner join t2 on t1.c1=t2.c1 where t1.c2='A';

1   #NSET2: [4, 24502, 296]

2     #PRJT2: [4, 24502, 296]; exp_num(8), is_atom(FALSE)

3       #HASH2 INNER JOIN: [4, 24502, 296];  KEY_NUM(1); KEY(T1.C1=T2.C1) KEY_NULL_EQU(0)

4         #SLCT2: [1, 250, 148]; T1.C2 = 'A'

5           #CSCN2: [1, 10000, 148]; INDEX33555599(T1)

6         #CSCN2: [1, 10000, 148]; INDEX33555600(T2)

哈希连接比较消耗内存如果系统有很多这种连接时,需调整以下 3 个参数:

参数名

说明

HJ_BUF_GLOBAL_SIZE

HASH 连接操作符的数据总缓存大小 ()>=HJ_BUF_SIZE),系统级参数,以兆为单位。有效值范围(10~500000)

HJ_BUF_SIZE

单个哈希连接操作符的数据总缓存大小,以兆为单位。有效值范围(2~100000)

HJ_BLK_SIZE

哈希连接操作符每次分配缓存( BLK )大小,以兆为单位,必须小于 HJ_BUF_SIZE。有效值范围(1~50)

13.MERGE JOIN:归并排序连接

归并排序连接需要两张表的连接列都有索引,对两张表扫描索引后按照索引顺序进行归并。

-- 对连接列创建索引CREATE INDEX IDX_T1_C1C2 ON T1(C1,C2);

select /*+use_merge(t1 t2)*/t1.c1,t2.c1 from t1 inner join t2 on t1.c1=t2.c1 where t2.c2='b';

1   #NSET2: [13, 24725, 56]

2     #PRJT2: [13, 24725, 56]; exp_num(2), is_atom(FALSE)

3       #SLCT2: [13, 24725, 56]; T2.C2 = 'b'

4         #MERGE INNER JOIN3: [13, 24725, 56]; KEY_NUM(1); KEY(COL_0 = COL_0) KEY_NULL_EQU(0)

5           #SSCN: [1, 10000, 4]; IDX_C1_T1(T1)

6           #BLKUP2: [1, 10000, 52]; IDX_T2_C1(T2)

7             #SSCN: [1, 10000, 52]; IDX_T2_C1(T2)

(三)ET 工具

ET 工具是 DM 数据库自带的 SQL 性能分析工具,能够统计 SQL 语句执行过程中每个操作符的实际开销,为 SQL 优化提供依据以及指导。

1.功能的开启/关闭

ET 功能默认关闭,可通过配置 INI 参数中的 ENABLE_MONITOR=1、MONITOR_SQL_EXEC=1 开启该功能。

--两个参数均为动态参数,可直接调用系统函数进行修改

SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);

SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',1);

--会话级别修改只在当前会话生效

SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC',1);

--关闭 ET

SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',0);

SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',0);

注意

ET 功能的开启将对数据库整体性能造成一定影响,优化工作结束后尽量关闭该功能以提升数据库整体运行效率;DM数据库新版本的开启ET功能时需要设置:ENABLE_MONITOR = 1(默认打开)MONITOR_TIME = 1(默认打开)MONITOR_SQL_EXEC = 1(设置成1)。

(四)dbms_sqltune 工具

DBMS_SQLTUNE 包提供一系列实时 SQL 监控的方法。当 SQL 监控功能开启后,DBMS_SQLTUNE 包可以实时监控 SQL 执行过程中的信息,包括:执行时间、执行代价、执行用户、统计信息等情况。

使用前提:建议会话级开启参数 MONITOR_SQL_EXEC=1,而 MONITOR_SQL_EXEC 在达梦数据库中一般默认是 1,无需调整。

ALTER SESSION SET 'MONITOR_SQL_EXEC' = 1;

<执行待优化SQL>

select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_EXEC_ID=>1213701) from dual;

dbms_sqltune 系统包相比 ET 功能更强大,能够获取 IO 操作量,查看真实执行计划,每个操作符消耗占比和相应的花费时间,还能看出每个操作符执行的次数,非常便于了解执行计划中瓶颈位置。

dbms_sqltune 功能远不止定位执行计划瓶颈,还拥有调优助手功能(建议性提示建某索引和收集某统计信息)。

(五)存储过程调试

在 DM 数据库中,我们可以利用 DM PL/SQL 进行存储过程及函数的编写。有时,我们编写的程序块中可能会有 BUG 导致编译失败,这种情况下就需要用到相关工具来进行调试。本章节主要介绍两种存储过程的调试方法。

1.图形化界面工具进行调试

在有图形化界面的情况下,我们可以利用管理工具来进行匿名块的调试。

(1)使用匿名块调试

开启系统包 DEBUG SYSTEM。【工具包】->DEBUG SYSTEM-> 右键->【启用】;

点击上方的【调试】按钮进入调试。

(2)创建测试存储过程,并进行调试

创建测试存储过程。

--当i到3的时候就会报除0错误DECLARE

--变量

aa int;BEGIN

--调试语句

for i in 1..3

loop

aa = 1 / (3-i);

print aa;

end loop;

END

进入调试,点击【进入】按钮,会依照代码逻辑进行分步调试,显示区域会显示当前变量执行结果。若遇到报错会终止调试,并显示报错内容,可根据报错内容进行代码修改。

2.DMDBG 进行调试

当我们没有图形界面,或者通过远程连接服务器的时候,我们也可以利用 DM 提供的命令行调试工具 dmdbg ,来完成同样的任务。

(1)登录 dmdbg。dmdbg 与 disql 同级目录,都在 dmdbms/bin 目录下,登录方式也与 disql 类似:

cd /dmdbms/bin

./dmdbg SYSDBA/SYSDBA@LOCALHOST:5236

--可以使用 help 命令查看参数

DEG> help

(2)引用存储过程。在 disql 中创建如下测试存储过程,然后在 DBG 中把 call TEST_DMDBG; 放到 SQL 内执行,如下所示:

--注意调试前确保已经开启系统包 DEBUG SYSTEM--登录disql,在disql中创建如下测试存储过程

create or replace procedure TEST_DEBUGas

aa int;begin

for i in 1..3

loop

aa = 1 / (3-i);

print aa;

end loop;end;

--登录dmdbg,把 call TEST_DMDBG; 放到 SQL 内执行

DBG> sql call TEST_DMDBG;

(3)添加断点。从头开始调试,将断点放到最开始的位置,可以在需要的行数打上断点,如下所示:

DBG> B 0

Breakpoint 1 at @dbg_main, line: 1@{call TEST_DMDBG;}

(4)开始调试。

DBG> r

Breakpoint 1,  line: 1@{call TEST_DMDBG;}

(5)进入循环里调试。

DBG> s

SYSDBA.TEST_DMDBG line: 5       @{   for i in 1..3}

DBG> s

SYSDBA.TEST_DMDBG line: 7       @{     aa = 1 / (3-i);}

(6)查看当前的堆栈。

DBG> bt

\#0      SYSDBA.TEST_DMDBG()     line: 7@{     aa = 1 / (3-i);}

\#1      @dbg_main       line: 1@{call TEST_DMDBG;}

(7)查看当前变量的数值。

--可以通过 P 变量名的方式输出打印

DBG> p aa

$3 = 0--当 i 到3的时候就会报除0错误

DBG> s

[TEST_DMDBG] 除0错误.error code=-6103--报错停止

三、SQL 语句优化

关于查询语句,有以下几点特征:

  • 返回数据越多,语句执行时间越长;
  • 分页是一个优化重点,order by 排序大小由结果集大小决定,过大会在临时表空间排序,性能降低;
  • 一些语句会隐式排序,比如 uinon group by;
  • buffer 过小,数据页频繁的换入换出。

关于优化 sql 语句:

  • 通过各种手段减少 sql 执行过程中的 IO 代价,内存中的计算,临时表使用等;
  • 表与表之间的关系,即关联条件之间的数据对应关系;
  • 表数据量大小,对于 OLTP 是否满足小表驱动大表;
  • sql 返回结果集多少,如果返回结果集少,sql 优化余地较大;
  • 合理利用索引(组合索引)的特点,虽然维护索引也需要代价,但是对于查询来说,很多时候效果立竿见影。

关于访问和连接方法:

  • 全表扫描访问;
  • 索引扫描访问;
  • 嵌套循环连接;
  • 哈希连接;
  • 归并连接;
  • 半连接、反连接;
  • n 张表至少有 n-1 次连接。

 (一)索引

索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录。

索引结构:最常见的索引结构为 B*树索引

最顶层的为根节点,最底层的为叶子节点,中间层为内节点。实际使用当中一般不止 3 层(取决于数据量大小),除根节点以及叶子节点以外仅为内节点。对于一个 m 阶(本例中 m=2)的 B*树存储结构有以下几个特点:

  • 每个结点最多有 m 个子结点。
  • 除了根结点和叶子结点外,每个结点最少有 m/2(向上取整)个子结点。
  • 如果根结点不是叶子结点,那根结点至少包含两个子结点。
  • 所有的叶子结点都位于同一层。
  • 每个结点都包含 k 个元素,这里 m/2 ≤ k < m,这里 m/2 向下取整。
  • 每个节点中的元素从小到大排列。
  • 每个元素左结点的值都小于或等于该元素,右结点的值都大于或等于该元素。
  • 所有的非叶子节点只存储关键字信息。
  • 所有的叶子结点中包含了全部元素的信息。
  • 所有叶子节点之间都有一个链指针。

可以看出在该存储结构中查找特定数据的算法复杂度为 O(log2N),查找速度仅与树高度有关。
    对于聚集索引叶子节点存储的元素是数据块即为整行数据,对于非聚集索引叶子节点存储的元素是索引字段的所对应的聚集索引的值或 rowid,如果需要获取其它字段信息需要根据聚集索引的值或 rowid 回表 (BLKUP) 进行查询。

索引适用范围:

在以下场景下可考虑创建索引:

  • 仅当要通过索引访问表中很少的一部分行(1%~20%)。
  • 索引可覆盖查询所需的所有列,不需额外去访问表。

注意

对于一个表来说索引并非越多越好,过多的索引将影响该表的 DML 效率。

存在下列情况将导致无法使用索引:

组合索引中,条件列中没有组合索引的首列。

  • 条件列带有函数或计算。
  • 索引排序是按照字段值进行排序的,字段值通过函数或计算后的值索引无法获取。
  • 索引过滤性能不好时。

建立索引的原则:

  • 建立唯一索引。唯一索引能够更快速地帮助我们进行数据定位;
  • 为经常需要进行查询操作的字段建立索引;
  • 对经常需要进行排序、分组以及联合操作的字段建立索引;
  • 在建立索引的时候,要考虑索引的最左匹配原则(在使用 SQL 语句时,如果 where 部分的条件不符合最左匹配原则,可能导致索引失效,或者不能完全发挥建立的索引的功效);
  • 不要建立过多的索引。因为索引本身会占用存储空间;
  • 如果建立的单个索引查询数据很多,查询得到的数据的区分度不大,则考虑建立合适的联合索引;
  • 尽量考虑字段值长度较短的字段建立索引,如果字段值太长,会降低索引的效率。

(二)SQL 语句改写

DM 数据库针对 SQL 语句有以下常见几种改写方法:

1.优化 GROUP BY

提高 GROUP BY 语句的效率,可以在 GROUP BY 之前过滤掉不需要的内容。

--优化前

SELECT JOB,AVG(AGE) FROM TEMP

GROUP BY JOB HAVING JOB = 'STUDENT' OR JOB = 'MANAGER';

--优化后

SELECT JOB,AVG(AGE) FROM TEMP

WHERE JOB = 'STUDENT' OR JOB = 'MANAGER' GROUP BY JOB;

2.用 UNION ALL 替换 UNION

当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果集合会以 UNION ALL 的方式被合并,在输出最终结果前进行排序。用 UNION ALL 替代 UNION, 这样排序就不必要了,效率就会因此得到提高。

注意

UNION 将对结果集合排序,这个操作会使用到 SORT_AREA_SIZE 这块内存,对于这块内存的优化也很重要;UNION ALL 将重复输出两个结果集合中相同记录,要从业务需求判断使用 UNION ALL 的可行性。

--优化前

SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'

UNION

SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';

 --优化后

SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'

UNION ALL

SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';

3.用 EXISTS 替换 DISTINCT

当 SQL 包含一对多表查询时,避免在 SELECT 子句中使用 DISTINCT,一般用 EXISTS 替换 DISTINCT 查询更为迅速。

--优化前

SELECT DISTINCT USER_ID,BILL_ID FROM USER_TAB1 D,USER_TAB2 E

WHERE D.USER_ID= E.USER_ID;

--优化后

SELECT USER_ID,BILL_ID FROM USER_TAB1 D WHERE EXISTS(SELECT 1 FROM USER_TAB2 E WHERE E.USER_ID= D.USER_ID);

4.多使用 COMMIT

可以在程序中尽量多使用COMMIT,这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少。
COMMIT 所释放的资源:

  • 回滚段上用于恢复数据的信息;
  • 被程序语句获得的锁;
  • redo log buffer 中的空间;
  • 为管理上述 3 种资源中的内部花销。

 5.用WHERE子句替换HAVING子句

避免使用 HAVING 子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、总计等操作,可以通过 WHERE 子句限制记录的数目。on、where、having 三个都可以加条件子句,其中,on 是最先执行,where 次之,having 最后。

  • on 是先把不符合条件的记录过滤后才进行统计,在两个表联接时才用 on;
  • 在单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,where 和 having 结果是一样的,但 where 比 having 快;
  • 如果涉及到计算字段,where 的作用时间是在计算之前完成,而 having 是在计算后才起作用,两者的结果会不同;
  • 在多表联接查询时,on 比 where 更早起作用。首先会根据各个表之间的关联条件,把多个表合成一个临时表后,由 where 进行过滤再计算,计算完再由 having 进行过滤。

6.用TRUNCATE替换DELETE

当删除表中的记录时,在通常情况下, 回滚段用来存放可以被恢复的信息。如果没有 COMMIT 事务,会将数据恢复到执行删除命令之前的状况;而当运用 TRUNCATE 时,回滚段不再存放任何可被恢复的信息。当命令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短。

注意

TRUNCATE 只在删除全表适用,TRUNCATE 是 DDL 不是 DML。

7.用 EXISTS 替换 IN、用 NOT EXISTS 替换 NOT IN

在基于基础表的查询中可能会需要对另一个表进行联接。在这种情况下, 使用 EXISTS (或 NOT EXISTS )通常将提高查询的效率。在子查询中,NOT IN 子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN 都是最低效的(要对子查询中的表执行一个全表遍历),所以尽量将 NOT IN 改写成外连接( Outer Joins )或 NOT EXISTS。

--优化前

SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0

AND A.ID IN(SELECT ID FROM TEMP1 WHERE NAME ='TOM');

--优化后

SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0

AND EXISTS(SELECT 1 FROM TEMP1 WHERE A.ID= ID AND NAME='TOM');

8.半连接优化

半连接也是子查询的一种,查询只返回主表数据,子查询作为条件过滤使用。exists 关注是否有返回行,取决于关联列,in 关注是否存在过滤数据,在半连接改写中理解这点很重要。

优化改写:半连接改 join 。

--改写前,已下两种写法特征就是执行计划出现 semi 关键字

--写法一:

select EMPNO, ENAME, JOB, MGR, HIREDATE

  from emp2

 where deptno in (select deptno from dept2)

--写法二:

 select EMPNO, ENAME, JOB, MGR, HIREDATE

  from emp2

 where exists (select deptno from dept2 where dept2.deptno = emp2.deptno)

--改写优化--当子查询中部门表中部门编号不存在重复改写如下:

    select emp2.EMPNO,

           emp2.ENAME,

           emp2.JOB,

           emp2.MGR,

           emp2.HIREDATE

      from emp2inner join dept2

        on dept2.deptno = emp2.deptno

--若存在数据重复先根据关联列去重再关联select dept2.*

  from (select distinct deptno from emp2) emp2

 inner join dept2on dept2.deptno = emp2.deptno

9.反连接优化

同半连接一样,查询也只返回主表数据,通过 not in 和 not exists 过滤,再改写的过程中特别要注意反连接 not in 对空值敏感。

--ept2 deptno 列不存在空值时,以下两种写法等价,当 not in 存在空时,无数据行返回,因此 not exists 改写 not in 需要加上 not is null

select * from emp2 where deptno not in (select deptno from dept2);

select * from emp2 e where not exists (select * from dept2 d where d.deptno = e.deptno)

--not in、 not exists 改写 left join

select * from emp2 E  where deptno not in (select deptno from dept2 D)

--反连接驱动是 E 表,被驱动是 D 表,所以改写 left join ,not in 表示不在此范围,即 emp2 有的部门编号,dept2 没有

--左连接会将右表没有的内容用 NULL 表示,所以关联后取 d.deptno is null 过滤select e.*

  from emp2 e

  left join dept2 d

    on d.deptno = e.deptno

 where d.deptno is null

(三)表设计优化

表设计优化可以从三个方面入手:选择合适的表类型、设置分区表、设置全局临时表。

1.表类型选择

达梦数据库提供了三种表类型:行存储表、列存储表(HUGE)和堆表。运维人员可根据实际需求选择合适的表类型。

表类型

描述

主要特征

适用场景

行存储表

行存储是以记录为单位进行存储的,数据页面中存储的是完整的若干条记录

1.按行存储 2.每个表都创建一个 B 树,并在叶子上存放数据

适用于高并发 OLTP 场景。

列存储表(HUGE)

列存储是以列为单位进行存储的,每一个列的所有行数据都存储在一起,而且一个指定的页面中存储的都是某一个列的连续数据。

1.按列存储 2.非事务型 HUGE 表:LOG NONE、LOG LAST、LOG ALL3.事务型 HUGE 表

适用于海量数据分析场景

堆表

堆表是指采用了物理 ROWID 形式的表,即使用文件号、页号和页内偏移而得到 ROWID 值,这样就不需要存储 ROWID 值,可以节省空间

1.数据页都是通过链表形式存储 2.可设置并发分支

并发插入性能较高

2.水平分区表

分区类型

  • 范围(range)水平分区:对表中的某些列上值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上;
  • 哈希(hash)水平分区:通过指定分区编号来均匀分布数据的一种分区类型,通过在 I/O 设备上进行散列分区,使得这些分区大小基本一致;
  • 列表(list)水平分区:通过指定表中的某个列的离散值集,来确定应当存储在一起的数据。例如,可以对表上的 status 列的值在('A','H','O')放在一个分区,值在('B','I','P')放在另一个分区,以此类推;
  • 多级分区表:按上述三种分区方法进行任意组合,将表进行多次分区,称为多级分区表。

分区优势

  • 减少访问数据
  • 操作灵活:可以操作分区 truncate、分区 drop、分区 add、分区 exchange

举例说明

select *  from range_part_tab

where deal_date >= TO_DATE('2019-08-04','YYYY-MM-DD')

and deal_date <= TO_DATE('2019-08-07','YYYY-MM-DD');

执行计划:

1 #NSET2:[24,18750,158]

2  #PRJT2:[24,18750,158];exp_num(6),is_atom(FALSE)

3   #PARALLEL:[24,18750,158];scan_type(GE_LE),key_num(0,1,1)

4    #SLCT2:[24,18750,158];[(RANGE_PART_TAB.DEAL_DATE >= var2 AND RANGE_PART_TAB.DEAL_DATE <= var4)]

5      #CSCN2:[73,500000,158];INDEX33555933(RANGE_PART_TAB)

--#PARALLEL:控制水平分区子表的扫描

  • 对主表和所有子表都收集统计信息
  • 对索引收集统计信息

注意

如果 SQL 中有可利用的索引,普通表也可能比分区表性能高。

3.全局临时表

当处理复杂的查询或事务时,由于在数据写入永久表之前需要暂时存储一些行信息或需要保存查询的中间结果,可能需要一些表来临时存储这些数据。DM 允许创建临时表来保存会话甚至事务中的数据。在会话或事务结束时,这些表上的数据将会被自动清除。

全局临时表类型

  • 事务级-ON COMMIT DELETE ROWS
  • 会话级-ON COMMIT PRESERVE ROWS

全局临时表优势

  • 不同 session 数据独立
  • 自动清理

举例说明

第一步:原始语句如下:

--T_1 视图(与 oracle 的 dblink 全表查询)

--T_1 视图的结构为

--(INIT_DATE int , BRANCH_NO int , FUND_ACCOUNT int , BUSINESS_FLAG int , remark varchar(32))

--T_2 表

--T_2 表的结构为

--(BRANCH_NO int,FUND_ACCOUNT int , prodta_no int,v_config_4662 varchar(32))

select a.init_date as oc_date,a.BRANCH_NO,a.FUND_ACCOUNT,a.BUSINESS_FLAG,a.remark,b.BRANCH_NO,b.FUND_ACCOUNT,b.prodta_no

from T_1 a,T_2 b

where init_date = 20181120

AND a.BRANCH_NO = b.BRANCH_NO

AND a.FUND_ACCOUNT = b.FUND_ACCOUNT

and instr(v_config_4662, ',' || b.prodta_no || ',')>0

and a.BUSINESS_FLAG in (2629,2630)

and nvl(a.remark,' ')not like '%实时TA%';

第二步:创建临时表 T1_20181122,将 T_1 视图中部分数据插入临时表中。

CREATE GLOBAL TEMPORARY TABLE "T1_20181122"

(init_date int,  BRANCH_NO int, FUND_ACCOUNT int,BUSINESS_FLAG int,remark varchar(32));

--插入dblink获取的数据到临时表

insert into T1_20181122

select *

from T_1 a

where init_date = 20181120

and a.BUSINESS_FLAG in (2629,2630)

and nvl(a.remark,' ')not like '%实时TA%';

第三步:语句改写。

select a.init_date as oc_date,a.BRANCH_NO,a.FUND_ACCOUNT,a.BUSINESS_FLAG,a.remark,b.BRANCH_NO,b.FUND_ACCOUNT,b.prodta_no

from T1_20181122 a, T_2 b

where a.BRANCH_NO = b.BRANCH_NO

AND a.FUND_ACCOUNT = b.FUND_ACCOUNT

and instr(v_config_4662, ',' || b.prodta_no || ',')>0;

执行计划:50 分钟 >>1 分钟。

--原语句执行计划

1 #NSET2:[11,1,1644]

  1. #PRJT2:[11,1,1644];exp_num(41),is_atom(FALSE)

3 #HASH2 INNER JOIN:[11,1,1644];KEY_NUM(2);

4 #SLCT2:[0,1,270];exp11>0

5 #CSCN2:[0,1,270];INDEX33560908(T_HSOTCPRODCASHACCT as B)

6 #HASH RIGHT SEMI JOIN2:[10,380,1374];n_keys(1)

7 #CONST VALUE LIST:[0,2,30];row_num(2),col_num(1),

8 #SLCT2:[10,380,1374];(A.INIT_DATE = var4 AND NOT(exp11 LIKE '%实时TA%'))

9 #PRJT2:[10,1000,1374];exp_num(13),is_atom(FALSE)

10 #REMOTE SCAN:[0,0,0] HIS_FUNDJOUR@HS08HIS

--改写后执行计划

1   #NSET2: [1, 1, 124]

2     #PRJT2: [1, 1, 124]; exp_num(8), is_atom(FALSE)

3       #HASH2 INNER JOIN: [1, 1, 124];  KEY_NUM(2); KEY(B.BRANCH_NO=A.BRANCH_NO AND B.FUND_ACCOUNT=A.FUND_ACCOUNT) KEY_NULL_EQU(0, 0)

4         #SLCT2: [1, 1, 60]; exp11 > 0

5           #CSCN2: [1, 1, 60]; INDEX33555476(T_2 as B)

6         #CSCN2: [1, 1, 64]; INDEX33555478(T1_20181122 as A)

4.hint优化sql

当统计信息已收集,且索引也按照需求建立,sql 执行效率仍然不符合预期,可以考虑添加 hint 方式来进行优化。

--例如:多个单表查询通过 union 连接后组成一个视图,然后视图通过 where 过滤,过滤条件在每个单表中过滤性较好,且存在索引,通过视图过滤无法使用索引,执行时间55s。select * from dms.view_da_base where ahdm = '00005fe8-b171-4292-b776-b53c3fd65923';

使用 hint 修改参数 VIEW_FILTER_MERGING 的值对视图条件进行优化,当参数值取 1 时表示尽可能地进行视图条件合并。

select /*+ VIEW_FILTER_MERGING(1) */ * from dms.view_da_base where ahdm = '00005fe8-b171-4292-b776-b53c3fd65923';

当系统在运行过程中,出现慢 sql 需要紧急进行优化处理时,可以在数据库端通过 SF_INJECT_HINT 函数将 hint 与 sql 进行绑定对慢 SQL 进行优化。

--设置 INI 参数 ENABLE_INJECT_HINT 为 1

SP_SET_PARA_VALUE(1,'ENABLE_INJECT_HINT',1);   

 --计划添加 hint 后的 SQL

select    /*+ VIEW_FILTER_MERGING(1) */  * from dms.view_da_base where ahdm = '00005fe8-b171-4292-b776-b53c3fd65923';

---模糊匹配 sql 进行 hint 绑定

 SF_INJECT_HINT('select * from dms.view_da_base where    ,', 'VIEW_FILTER_MERGING(1)', 'VIEW_HINT', 'to testfunction of injecting hint', TRUE, TRUE);

注意

此优化方式不推荐作为常规优化方法使用,特定场景优化或应急处理时使用。

达梦数据库 - 新一代大型通用关系型数据库 | 达梦在线服务平台

相关文章:

达梦SQL 优化简介

目录 一、定位慢 SQL &#xff08;一&#xff09;开启跟踪日志记录 1.跟踪日志记录配置 &#xff08;二&#xff09;通过系统视图查看 1.SQL 记录配置 2.查询方式 二、SQL分析方法 &#xff08;一&#xff09;执行计划 1.概述 2.查看执行计划 &#xff08;二&#x…...

题解:CF1070B Berkomnadzor

CF1070B Berkomnadzor 题解 解题思路 不难想到将 IP 地址转化为二进制后插入一个字典树中&#xff0c;转化后二进制的长度就是 x x x 的长度。我们需要记录每个串结尾的颜色&#xff0c;不妨设黑名单为 1 1 1&#xff0c;白名单为 0 0 0&#xff0c;初始时每个位置的颜色是…...

shell 学习笔记:数组

目录 1. 定义数组 2. 读取数组元素值 3. 关联数组 4. 在数组前加一个感叹号 ! 可以获取数组的所有键 5. 在数组前加一个井号 # 获取数组的长度 6. 数组初始化的时候&#xff0c;也可以用变量 7. 循环输出数组的方法 7.1 for循环输出 7.2 while循环输出 7.2.1 …...

计算机基础知识复习9.5

数据交换 电路交换&#xff1a;交换信息的两个主机之间简历专用通道&#xff0c;传输时延小&#xff0c;实时性强&#xff0c;效率低&#xff0c;无法纠正错误。 报文交换&#xff1a;信息拆分成小包(报文&#xff09;大小无限制&#xff0c;有目的/源等信息提高利用率。有转…...

spark.sql

from pyspark.sql import SparkSession from pyspark.sql.functions import col, count, mean, rank, row_number, desc from pyspark.sql.window import Window from pyspark.sql.types import StructType, StructField, StringType, IntegerType# 初始化 SparkSession 对象 s…...

2024 数学建模高教社杯 国赛(A题)| “板凳龙”舞龙队 | 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;运用等距螺线&#xff0c;多目标规划等强大工具&#xff0c;构建了这一题的详细解答哦&#xff01; 为大家量身打造创新解决方案。小秘籍团队&#xff0c;始终引领着建模问题求解的风潮。 抓紧小秘籍&am…...

kaggle注册收不到验证码、插件如何下载安装

综合这三个来看&#xff0c; 1.插件下载用的大佬给的分享链接 2.下载好压缩包以后需要解压缩 Header Editor插件网盘下载安装教程 - 哔哩哔哩 (bilibili.com) 3.安装插件时没找到crx文件&#xff0c;在浏览器插件界面点击“加载解压缩的扩展” 4.复制网址到插件里&#xff…...

k8s相关技术栈

文章目录 一、k8s技术栈核心组件常见工具和服务生态系统 二、k8s服务组件控制平面组件节点组件附加组件和服务 三、k8s 常见资源核心资源扩展资源 四、系列文档其他参考 一、k8s技术栈 Kubernetes&#xff08;常被简称为 K8s&#xff0c;其中 “K” 代表 “Kubernetes” 的首字…...

uniapp h5项目页面中使用了iframe导致浏览器返回按键无法使用, 返回不了上一页.

uniapp h5项目页面中使用了iframe导致浏览器返回按键无法使用, 返回不了上一页. 在 UniApp 中使用 iframe 加载外部页面时&#xff0c;可能会遇到返回键行为不符合预期的问题。这是因为 iframe 本身可以包含多个页面的历史记录&#xff0c;而默认情况下&#xff0c;浏览器的返…...

《2024网络安全十大创新方向》

网络安全是创新驱动型产业&#xff0c;技术创新可以有效应对新的网络安全挑战&#xff1b;或是通过技术创新降低人力成本投入&#xff0c;提升企业运营效率。为推动行业技术创新、产品创新与应用创新&#xff0c;数说安全发布《2024年中国网络安全十大创新方向》&#xff0c;涵…...

深入解析反射型 XSS 与存储型 XSS:原理、危害与防范

在网络安全领域&#xff0c;跨站脚本攻击&#xff08;XSS&#xff09;是一种常见的安全漏洞。XSS 攻击可以分为反射型 XSS 和存储型 XSS 两种类型。本文将详细介绍这两种类型的 XSS 攻击的原理、危害和防范措施。 一、反射型 XSS 1、原理 反射型 XSS 攻击也称为非持久性 XSS …...

【STM32+HAL库】---- 驱动MAX30102心率血氧传感器

硬件开发板&#xff1a;STM32F407VET6 软件平台&#xff1a;cubemaxkeilVScode1 MAX30102心率血氧传感器工作原理 MAX30102传感器是一种集成了红外光源、光电检测器和信号处理电路的高度集成传感器&#xff0c;主要用于心率和血氧饱和度的测量。以下是MAX30102传感器的主要特点…...

InstantX团队新作!基于端到端训练的风格转换模型CSGO

由InstantX团队、南京理工大学、北京航空航天大学以及北京大学联合提出了一种基于端到端训练的风格转换模型 CSGO&#xff0c;它采用独立的特征注入明确地解耦内容和风格特征。统一的 CSGO 实现了图像驱动的风格转换、文本驱动的风格化合成和文本编辑驱动的风格化合成。大量实验…...

Nginx安全性配置

文章目录 引言I Nginx简单的安全性配置禁止特定的HTTP方法限制URL长度禁止某些用户代理限制请求速率连接限制禁止访问某些文件类型II 常见的安全规则防御CC攻击User-Agent过滤GET-URL过滤GET-参数过滤POST过滤(sql注入、xss攻击 )引言 Nginx本身并不具备复杂的防火墙规则定制…...

k8s单master多node环境搭建-k8s版本低于1.24,容器运行时为docker

k8s 1.20.6单master多node环境搭建 1.环境规划2.初始化服务器1&#xff09;配置主机名2&#xff09;设置IP为静态IP3&#xff09;关闭selinux4&#xff09;配置主机hosts文件5&#xff09;配置三台主机之间免密登录6&#xff09;关闭交换分区swap&#xff0c;提升性能7&#xf…...

taro ui 小程序at-calendar日历组件自定义样式+选择范围日历崩溃处理

taro ui 日历文档 目录 单选标记时间&#xff1a; 效果&#xff1a; template&#xff1a; data&#xff1a; methods: 日历--范围选择&#xff1a; 效果&#xff1a; template&#xff1a; data&#xff1a; methods&#xff1a; 日历--间隔多选&#xff1a;利用标…...

ARM发布新一代高性能处理器N3

简介 就在2月21日&#xff0c;ARM发布了新一代面向服务器的高性能处理器N3和V3&#xff0c;N系列平衡性能和功耗&#xff0c;而V系列则注重更高的性能。此次发布的N3&#xff0c;单个die最高32核&#xff08;并加入到CCS&#xff0c;Compute Subsystems&#xff0c;包含Core&a…...

基于Pytorch框架的深度学习U2Net网络天空语义精细分割系统源码

第一步&#xff1a;准备数据 头发分割数据&#xff0c;总共有10276张图片&#xff0c;里面的像素值为0和1&#xff0c;所以看起来全部是黑的&#xff0c;不影响使用 第二步&#xff1a;搭建模型 级联模式 通常多个类似U-Net按顺序堆叠&#xff0c;以建立级联模型&#xff0c…...

50ETF期权和股指期权有什么区别?ETF期权应该怎么做?

今天期权懂带你了解50ETF期权和股指期权有什么区别&#xff1f;ETF期权应该怎么做&#xff1f;ETF是对个股期权&#xff0c;股指期权是对应该股指期货的&#xff0c;那么股指期权和etf期权有什么区别&#xff1f; 股指期权怎么交易 股指期权交易要开通股指期货账户&#xff0…...

JS设计模式之“神奇的魔术师” - 简单工厂模式

引言 在JavaScript开发中&#xff0c;我们经常需要创建和管理各种对象&#xff0c;而简单工厂模式就是一种最简单的用来创建对象的设计模式。 简单工厂模式通过一个工厂类来创建相似的对象&#xff0c;而无需直接使用具体类来实例化对象。这样可以将对象的创建过程与使用过程…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...