SQL 语言是关系型数据库与应用交互的重要途径,书写高效率的 SQL 是每一个 DBA 和开发人员必备的技能。本文以调整 SQL 执行效率为最终目标,给大家介绍如何查看 Informix 的 SQL 执行计划,如何通过统计信息,SQL Directives 调整执行计划,如何通过 SQL Drill-down 监控 SQL 的执行效率,并且总结了书写 SQL 语句时若干需要注意的地方,可以作为一个实用的 SQL Checklist 使用。

SQL 执行计划

关于执行计划,我们可以把它简单的理解成 SQL 语句执行时访问数据的方式。执行计划的优劣是影响 SQL 执行效率的重要因素。它包括:查询优化器认为最优的数据访问路径,返回记录数的估计值,SQL 的相对开销值,以及其他附属信息。

获取执行计划

获取执行计划有多种方式:

1. 在服务器上直接执行 SQL 语句 set explain on 得到当前 session 中 SQL 的执行计划描述文件,默认名称为:sqexplain.out,

具体方式和操作如下:

在运行 IDS 的服务器上打开 dbaccess,通过 dbaccess 运行如下 SQL 语句:

set explain on; 
select first 10 * from customer c, cust_calls u  
where c.customer_num = u.customer_num order by 1;

则在当前目录下生成 sqexplain.out 文件,内容如下:

QUERY: (OPTIMIZATION TIMESTAMP: 12-31-2009 10:56:35) ------ select first 10 c.customer_num, c.lname, c.company, c.phone, u.call_dtime, u.call_descr from customer c, cust_calls u where c.customer_num = u.customer_num order by 1; Estimated Cost: 2326384 Estimated # of Rows Returned: 4318039 1) informix.c: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) 2) informix.u: INDEX PATH (1) Index Keys: customer_num call_dtime (Serial, fragments: ALL) Lower Index Filter: informix.c.customer_num = informix.u.customer_num NESTED LOOP JOIN Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 c t2 u type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 1 10000028 1 00:00.00 300003 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 10 4318026 10 00:00.00 0 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 10 4318039 00:00.00 2326384

2. 如果我们不是直接在服务器上执行 SQL,而是通过应用程序远程连接到服务器,同样可以使用 set explain on,但是此时 sqexplain.out 默认位置为当前用户的主目录下,如果使用 Informix 用户运行,则文件产生在 /home/Informix/ 目录下。

3. 通过 onmode – Y

比如我们有一个 session 连接到服务器,sessionID 为 22,则可以通过执行:

onmode – Y 22

打开针对该 session 所有的 SQL 语句的执行计划生成功能,生成结果在用户主目录下,例如 /home/Informix,文件名称格式为 sqexplain.out.<session_id>,也就是 /home/Informix/sqexplain.out.22,当然我们也可以通过”set explain file to“参数指定 sqexplain.out 的具体位置。

4. OAT

在打开 SQLtracing 功能的情况下,我们可以通过 OAT 工具查看,具体位置为:Performance Analysis>SQL Explorer>SQL>Query Tree,如下图 :

图 1. 通过 OAT 查看执行计划
图 1. 通过 OAT 查看执行计划

5. 通过第三方工具

例如 ServerStudio:

图 2. ServerStudio 查看执行计划(查看大图)
图 2. ServerStudio 查看执行计划

6. 通过系统表

如果 SQLtracing 打开,实际上我们可以在以下系统表中找到每条被追踪 SQL 的执行计划:

 syssqltrace sqltrace_iter sqltrace_hvar.

一般,一条 SQL 语句的执行对应 syssqltrace 中一条记录,对应 sqltrace_iter 的多条记录。

执行计划分析示例

一般来说,执行计划包含以下几个部分的信息:

  • 关于 SQL 的基本信息:包括 SQL 语句本身,估算的执行代价,和估算的返回记录数目。
  • 执行计划:包括表的访问方式,连接方式,访问顺序,对索引和分区的处理等信息。
  • 执行计划的统计信息:执行计划中每一步的更详细的信息,这部分只有 SQL 真正执行以后才有,如果设置了 SET EXPLAIN ON AVOID_EXECUTE,则不产生。

当我们怀疑某个 SQL 的执行效率有问题时,需要首先检查并确认它的执行计划是否合适,从而保证系统的效率。

实例 1:表的访问方式,sequencial scan 与 index scan

我们有 customer_t 数据表,1000000 行数据,在 customer_num 上建立有唯一索引:’ 169_81 ’ ,并且刚刚做过高级别的统计信息更新。以下实例表明 sequencial scan 还是 index scan 在效率上有很大的差别。

 [Informix@informix2 sqltuning]$ time echo "set explain on; select count(city) from customer_t where customer_num < 2000000"| dbaccess demodb Database selected. Explain set. (count) 218739 1 row(s) retrieved. Database closed. real 0m21.602s user 0m0.007s sys 0m0.011s

执行计划为:

 QUERY: (OPTIMIZATION TIMESTAMP: 01-05-2010 11:47:04) ------ select count(city) from customer_t where customer_num < 2000000 Estimated Cost: 24532 Estimated # of Rows Returned: 1 1) informix.customer_t: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) Upper Index Filter: informix.customer_t.customer_num < 2000000 Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 customer_t type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 218739 218740 218739 00:31.66 24532 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 218739 00:32.82 [Informix@informix2 sqltuning]$ time echo "set explain on; 
select {+avoid_index(customer_t ' 201_107' )} count(city)from customer_t where customer_num < 2000000"| dbaccess demodb Database selected. Explain set. (count) 218739 1 row(s) retrieved. Database closed. real 0m13.442s user 0m0.008s sys 0m0.009s

执行计划为:

 QUERY: (OPTIMIZATION TIMESTAMP: 01-05-2010 11:30:42) ------ select {+avoid_index(customer_t ' 201_107' )} count(city) 
from customer_t where customer_num < 2000000 DIRECTIVES FOLLOWED: AVOID_INDEX ( customer_t 201_107 ) DIRECTIVES NOT FOLLOWED: Estimated Cost: 101433 Estimated # of Rows Returned: 1 1) informix.customer_t: SEQUENTIAL SCAN (Serial, fragments: ALL) Filters: informix.customer_t.customer_num < 2000000 Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 customer_t type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 218739 333333 1000000 00:31.92 101433 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 218739 00:32.65

可以看出,使用 indexscan 的方式访问速度反而会慢很多,原因是我们访问的数据占数据表的比例很大,使用 index 得不偿失,而优化器没有能够正确的考虑这种情况,因而经过修正的访问计划为优。同样我们也可以通过实验验证,如果我们查询的范围缩小,例如:查询条件为 customer_num<1000, 则情况正好相反。

实例 2:连接方式

我们有 orders_t 数据表,5000000 行数据,在 customer_num 上建立有非唯一索引:’ idx_0 ’, 并且刚刚做过高级别的统计信息更新。以下实例表明连接循序的在效率上有很大的差别。

 [Informix@informix2 sqltuning]$ time echo "set explain on; select count(*) from orders_t o, customer_t c where o.customer_num = c.customer_num " | dbaccess demodb Database selected. Explain set. (count(*)) 277090 1 row(s) retrieved. Database closed. real 0m22.104s user 0m0.008s sys 0m0.012s

执行计划为:

 QUERY: (OPTIMIZATION TIMESTAMP: 01-02-2010 12:17:19) ------ select count(*) from orders_t o, customer_t c where o.customer_num = c.customer_num Estimated Cost: 725139 Estimated # of Rows Returned: 1 1) informix.c: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Serial, fragments: ALL) 2) informix.o: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Serial, fragments: ALL) Lower Index Filter: informix.o.customer_num = informix.c.customer_num NESTED LOOP JOIN Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 c t2 o type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 1000000 1000000 1000000 00:13.66 40687 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 277090 5000000 277090 01:42.06 1 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 277090 1211539 01:57.39 725140 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 277090 01:58.33 [Informix@informix2 sqltuning]$ time echo "set explain on; select {+ordered} count(*) from orders_t o, customer_t c where o.customer_num = c.customer_num " | dbaccess demodb Database selected. Explain set. (count(*)) 277090 1 row(s) retrieved. Database closed. real 0m38.978s user 0m0.007s sys 0m0.008s

执行计划为:

 QUERY: (OPTIMIZATION TIMESTAMP: 01-02-2010 12:15:17) ------ select {+ordered} count(*) from orders_t o, customer_t c where o.customer_num = c.customer_num DIRECTIVES FOLLOWED: ORDERED DIRECTIVES NOT FOLLOWED: Estimated Cost: 3394422 Estimated # of Rows Returned: 1 1) informix.o: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Serial, fragments: ALL) 2) informix.c: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Serial, fragments: ALL) Lower Index Filter: informix.o.customer_num = informix.c.customer_num NESTED LOOP JOIN Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1                        o t2                        c type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 5000000 5000000 5000000 00:57.07 185667 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 277090 1000000 277090 02:17.78 1 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 277090 1211539 03:21.09 3394422 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 277090 03:22.00

可以看出,连接的循序不同时,查询的执行时间有很大的差别,优化器选择的连接顺序为最优。

当然执行计划涉及到的内容非常丰富,这里只是举了最简单的例子,在实际应用中需要综合考虑各种情况。


统计信息

统计信息基本知识

统计信息是指数据库系统表中记录的关于业务数据的基本情况,包括一个表的行数、占用的数据页数、数据值分布情况,以及索引相关信息等,这些都是查询优化器选择执行计划的重要依据。没有统计信息、不准确的统计信息、都容易导致优化器选择效率低的执行计划。

统计信息存储与以下系统表中:

  • SYSTABLES: 表的索引情况,表中的行数
  • SYSCOLUMNS:列的次小值,列的次大值
  • SYSINDEXES:索引的级数,叶子节点数目,不同值的数量,cluster 程度
  • SYSFRAGMENTS:关于表分区或者索引分区的统计信息
  • SYSDISTRIB:数据分布情况

怎样更新统计信息

我们可以通过 SQL: “update statistics” 更新某个表某个列或者全部列的统计信息,统计信息有 low、medium、high 三种模式,其中 low 不生成数据分布信息,medium 以统计估算的方式生成数据分布信息,high 以精确的方式生成数据分布信息。针对 medium 方式我们可以指定 percent 和 confidence 参数,对于 high 我们可以指定需要的 percent 参数。Percent 参数是一个百分比,它的最大值为 10(10%),它的倒数就是统计区间的个数,统计区间越多则统计信息越精确。confidence参数为采样的可信度,越高采样越精确。

另外在 IDS11 中,在表上创建索引时,自动更新基本统计信息,如新创建的索引信息,数据表的行数。

实例

例如需要更新表 customer_t 的 customer_num 列的统计信息,可以使用以下语句:

 update statistics for table customer_t(customer_num); 
或者update statistics low for table customer_t(customer_num);
 update statistics medium for table customer_t(customer_num); 
或者update statistics medium for table customer_t(customer_num) resolution 2.5 0.95;
 update statistics high for table customer_t(customer_num); 
或者 update statistics high for table customer_t(customer_num) resolution 0.5;

如果要删除分布信息,可以使用以下语句 :

 update statistics for table customer_t(customer_num) drop distributions;

如果要查看数据表的数据分布信息,可以使用 dbschema:

例如有测试数据表 test1, 有 100 行记录。具体查看方式和输出为 :

 [Informix@informix2 sqltuning]$ dbschema -d demodb -hd test1 DBSCHEMA Schema Utility INFORMIX-SQL Version 11.50.FC3 { Distribution for informix.statis_1.age Constructed on 2010-01-03 10:56:04.00000 High Mode, 10.000000 Resolution --- DISTRIBUTION --- ( 1) 1: ( 3, 3, 4) 2: ( 3, 3, 7) 3: ( 3, 3, 10) 4: ( 3, 3, 13) 5: ( 3, 3, 16) 6: ( 3, 3, 19) 7: ( 3, 3, 22) 8: ( 3, 3, 25) 9: ( 3, 3, 28) 10: ( 1, 1, 30) --- OVERFLOW --- 1: ( 4, 2) 2: ( 2, 30) }

可以看到一共有 7 个正常分布桶 (DISTRIBUTION),共有三列,其中第一列为该桶中数据值个数,第二列为该桶中不同的值的个数,第三列为该桶中数据的上限。DISTRIBUTION 用于表示数据在各个区间的分布情况,在以 medium、high 方式生成统计信息时,可以通过 resolution 关键词指定该分布百分比,例如比率为 10% 时,如果数据值个数足够的话,一般最多会有 100/10=10 个分布桶。

OVERFLOW 中只有两列,其中第一列为数据值重复的个数,第二列为该数据值。列中的某个数据值出现的次数多到一定程度时才在这里出现。比如这里,2 这个数值在该列中出现的次数为 4 次,30 这个数值出现的次数为 2 次。

当某个值的重复次数满足以下条件时,才放置到 OVERFLOW( 溢出桶 ) 中:

 Overflow = 25% * resolution * number_rows

统计信息对 SQL 执行效率的影响

实例 1

我们来看统计信息对访问方式的影响。

针对数据表 customer_t (1000000 行记录 ,customer_numz 值在 101 到 10000124 之间,在 customer_num 列上建有索引 ) 执行以下语句:

 select * from customer_t where customer_num > 1000

在统计信息更新之前,执行计划选择索引扫描,事实上此时,无论查询条件的选择性如何,都会选择索引扫描。

 [Informix@informix2 sqltuning]$ time echo "set explain on; select {+index(customer_t ' 183_96')} count(city) from customer_t where customer_num > 1000 " | dbaccess demodb ; tail sqexplain.out -n 20 Database selected. Explain set. (count) 999901 1 row(s) retrieved. Database closed. real 1m18.870s user 0m0.008s sys 0m0.013s Lower Index Filter: informix.customer_t.customer_num > 1000

在完成 low 模式的统计信息更新之后,我们发现执行计划转为使用全表扫描,并且执行速度大大加快:

 [Informix@informix2 sqltuning]$ time echo "set explain on; select count(city) from customer_t where customer_num > 1000 " | dbaccess demodb ; tail sqexplain.out -n 20 Database selected. Explain set. (count) 999901 1 row(s) retrieved. Database closed. real 0m13.964s user 0m0.005s sys 0m0.014s

此例说明,在没有基本信息的情况下,优化器很可能选择索引扫描,但实际上如果查询条件的选择性不好,则会导致性能问题。此例中的查询条件只能过滤掉很少的一部分数据,这种情况下优化器需要对表的基本情况有一个了解才能明智的放弃索引扫描而使用更有的全表扫描。

实例 2

我们来看统计信息对 join 顺序和方式的影响 :

我们有表 :

customer_t: 1000000 rows,在 customer_num 上建有索引,基本 (LOW) 统计信息为最新

orderts_t; 5000000 rows,在 customer_num 上建有索引,没有基本统计信息。

items_t: 67 rows,

考察如下 SQL 语句:

 select * from customer_t c, orders_t o, items_t i where c.customer_num = o.customer_num and i.order_num = o.order_num and c.customer_num < 10000000

如果 items_t 上没有基本统计信息,则

 [Informix@informix2 sqltuning]$ time echo "set explain on; select * from customer_t c, orders_t o, items_t i where c.customer_num = o.customer_num and i.order_num = o.order_num and c.customer_num < 10000000; " | dbaccess demodb Database selected. Explain set. customer_num 122 fname Cathy lname O'Brian 
……
……1 row(s) retrieved. Database closed. real 1m1.143s user 0m0.006s sys 0m0.012s

执行计划为 :

 QUERY: (OPTIMIZATION TIMESTAMP: 01-03-2010 17:44:32) ------ select * from customer_t c, orders_t o, items_t i where c.customer_num = o.customer_num and i.order_num = o.order_num and c.customer_num < 10000000 Estimated Cost: 1936048 Estimated # of Rows Returned: 111665344 1) informix.o: SEQUENTIAL SCAN (Serial, fragments: ALL) Filters: informix.o.customer_num < 10000000 2) informix.c: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) Lower Index Filter: informix.c.customer_num = informix.o.customer_num NESTED LOOP JOIN 3) informix.i: SEQUENTIAL SCAN DYNAMIC HASH JOIN Dynamic Hash Filters: informix.i.order_num = informix.o.order_num Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 o t2 c t3 i type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 4999964 1666667 5000000 00:35.52 358337 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 277088 999989 277088 02:37.55 1 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 277088 1666648 03:18.58 1608258 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t3 67 67 67 00:00.00 4 type rows_prod est_rows rows_bld rows_prb novrflo time est_cost ------------------------------------------------------------------------------ hjoin 1 111665376 67 277088 0 03:19.58 1936048
图 3. 统计信息更新前执行计划(查看大图)
图 3. 统计信息更新前执行计划

如果在 items_t 上更新基本统计信息以后,我们得到同样的查询结果,但是现执行速度大大加快 :

 [Informix@informix2 sqltuning]$ time echo "set explain on; select * from customer_t c, orders_t o, items_t i where c.customer_num = o.customer_num and i.order_num = o.order_num and c.customer_num < 10000000; " | dbaccess demodb Database selected. Explain set. customer_num 122 fname Cathy lname O'Brian 
……
……1 row(s) retrieved. Database closed. real 0m1.716s user 0m0.011s sys 0m0.008s

执行计划为:

 QUERY: (OPTIMIZATION TIMESTAMP: 01-03-2010 18:05:50) ------ select * from customer_t c, orders_t o, items_t i where c.customer_num = o.customer_num and i.order_num = o.order_num and c.customer_num < 10000000 Estimated Cost: 938099 Estimated # of Rows Returned: 1116654 1) informix.i: SEQUENTIAL SCAN 2) informix.o: INDEX PATH Filters: informix.o.customer_num < 10000000 (1) Index Keys: order_num (Serial, fragments: ALL) Lower Index Filter: informix.i.order_num = informix.o.order_num NESTED LOOP JOIN 3) informix.c: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) Lower Index Filter: informix.c.customer_num = informix.o.customer_num NESTED LOOP JOIN Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 i t2 o t3 c type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 67 67 67 00:00.05 4 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 1 1666667 1 00:00.05 1500 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 1 1116667 00:00.11 100652 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t3 1 999989 1 00:00.06 1 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 1 1116654 00:00.17 938099
图 4. 统计信息更新后执行计划(查看大图)
图 4. 统计信息更新后执行计划

比较二者,我们发现连接的顺序由 oct,转变为:oic,对表 orders_t 的访问方式由全表扫描转变为索引扫描,HASH-Join 转变为 NESTEDLOOP-Join。

由上面的例子可见统计信息对于执行计划和 SQL 执行效率的重要性,即使是最基本统计信息的缺失也会导致连锁反应,从而使得优化器选择效率低的执行计划。

关于使用统计更新的建议

  • high 模式的统计信息要占用大量资源,一般不需要对数据库的所有表,或者表的所有列进行 high 模式的统计。只需要对关键的列进行统计即可。对于符合索引,一般对第一个列做高级别的统计更新,后面的列做相应低级别的即可。数据库升级以后需要重新进行统计信息的更新。
  • IDS11 版本中 create index 执行以后,会自动对表进行 Low 级别的统计信息更新。不需要再额外的做 low 级别的更新。在老版本中,需要更新统计信息以后优化器才会利用 index。
  • IDS11.5 版本中还加入了自动统计信息更新功能,对于数据分布变化频繁的数据表,可以大大减少 DBA 的工作量; 具体操作方式可以搜索 AUTO UPDATE STATISTICS (AUS)。

SQL Directives

什么是 SQL Directives

简而言之,SQL Directives 就是一种通过在 SQL 语句中加入提示,达到强制修改执行计划的技术。

Informix 有哪些 SQL Directives

 Join-Order Directives:INDEX,AVOID_INDEX,INDEX_SJ,AVOID_INDEX_SJ,FULL,AVOID_FULL Join-Plan Directives:ORDERED Optimization-Goal Directives:USE_NL,USE_HASH,AVOID_NL,AVOID_HASH

怎样使用 SQL Directives

使用 Directives: ORDERED

按照 FROM 子句中出现的次序进行表连接:

示例:

 SELECT --+ORDERED c.x,c.y,b.z FROM a,b,c WHERE c.x=b.n AND b.z=a.z;

将先访问表 a,然后访问表 b 和 c,当表 a 和 b 都很小的时候这种执行计划速度会比其它顺序效率高。

使用 Directives: INDEX / AVOID_INDEX

指定使用或者避免使用某个索引。

示例:

 SELECT {+ORDERED, INDEX(a y), AVOID_INDEX(b n)} c.x,c.y,b.z FROM a,b,c WHERE c.x=b.n AND b.z=a.z;

这里我们指定必须使用表 a 的索引 y,而避免使用表 b 的索引 n。

使用 Directives: FULL / AVOID_FULL

指定使用全表扫描或者避免权表扫描。

示例:

 SELECT {+ORDERED, INDEX(a y), AVOID_INDEX(b n), FULL(c)} c.x,c.y,b.z FROM a,b,c WHERE c.x=b.n AND b.z=a.z;

这里我们指定了表的访问顺序,使用 a 的索引 y,不使用 b 的索引 n,对 c 表使用全表扫描。

使用 Directives: JOIN METHOD DIRECTIVES

强迫优化器使用或者避免使用某种连接方式,Nested Loop 或者 Hash Joins,包括:USE_NL/ AVOID_NL,USE_HASH/ AVOID_HASH。

示例:

 SELECT {+ORDERED, INDEX(a y), AVOID_INDEX(b n), FULL(c), USE_HASH(c/BUILD)} c.x,c.y,b.z FROM a,b,c WHERE c.x=b.n AND b.z=a.z;

这里我们指定了针对表 c 创建 hash 表。以 hashjoin 方式做连接。

使用 Directives: OPTIMIZATION GOAL

指定优化目标,包括:FIRST_ROWS,ALL_ROWS。

示例:

 SELECT {+ORDERED,FIRST_ROWS} c.x,c.y,b.z FROM a,b,c WHERE c.x=b.n AND b.z=a.z;

这里指定优化器选用有利于返回前几条记录的查询计划,比如,放弃使用 HASH-JOIN 方式,而使用 NESTEDLOOP-JOIN 方式。

外部 SQL Directives

在某种情况下,我们希望临时修改 SQL 的执行计划,或者希望在不修改应用的情况下调整 SQL 的执行计划,这时就用到了外部 Directives,我们可以针对一条 SQL 在系统表 sysdirectives 中添加相应的 Directives,当数据库执行 SQL 时,如果发现在 sysdirectives 表里有相应的 Directives,则应用之,即使 SQL 本身并没有带任何 Directives 信息。

打开和设置外部 SQL Directives

一般来说可以通过下面的方式打开:

ONCONFIG 文件中设置 EXT_DIRECTIVE 为 2

或者

ONCONFIG 文件中设置 EXT_DIRECTIVE 为 2,并且在需要考虑外部 Directives 的 Session 中执行“set environment IFX_EXTDIRECTIVES ‘ on ’”

设置外部 Directives

执行 SQL: SAVE EXTERNAL DIRECTIVES …… ACTIVE for ……

举例:

我们以 $Informix/demo/esqlc 下面的应用 demo2.ec 为例。demo2 中执行以下 SQL:

“select fname, lname from customer where lname < ?;”,我们来看如何不修改 demo2.ec 的情况下修改 SQL 的执行计划。

1. 首先,我们给 customer 的 lname 列建立 index,名称为“iddd1“

2. 打开全局 SQL Tracing,只监控我们关心的 database: demodb:

 echo " execute function 
sysadmin:task('set sql tracing on,1000,1, ’ high ’ ,'global')"| dbaccess demodb echo " execute function 
sysadmin:task('set sql tracing database add','demodb')"| dbaccess demodb

3. 编译并执行,demo2.ec:

 [Informix@informix2 esqlc]$ make demo2 /opt/IBM/Informix/bin/esql -o demo2 -I/opt/IBM/Informix/incl-I/opt/IBM/Informix/incl/esql demo2.ec [Informix@informix2 esqlc]$ demo2 DEMO2 Sample ESQL Program running. Column: fname Value: Ludwig Column: lname Value: Pauli Column: fname Value: Cathy Column: lname Value: O'Brian Column: fname Value: Alfred Column: lname Value: Grant DEMO2 Sample Program over.

4. 查看执行计划:

这里我们只是验证对数据表的扫描方式:

 [Informix@informix2 esqlc]$ echo "select sql_itr_info from syssqltrace st, syssqltrace_iter iter where sql_statement='select fname, lname from customer_t where lname < ?' and st.sql_id=iter.sql_id " | dbaccess sysmaster sql_itr_info Index Scan 1 row(s) retrieved. Database closed.

可以看到,默认情况下使用了 Index Scan。

5. 针对这条 SQL 语句添加外部 Directives:

 [Informix@informix2 esqlc]$echo "SAVE EXTERNAL DIRECTIVES {+AVOID_INDEX(customer_t iddd1)} ACTIVE FOR select fname, lname from customer_t  where lname < ?;" | dbaccess demodb

执行完毕后,我们可以看到 demodb:sysdirectives 中多了一条记录。因为这条记录的存在,demo2 中 SQL 的执行方式将发生变化。

6. 再次执行 demo2, 然后查看执行计划 :

我们得到的结果是:

 sql_itr_info Table Scan 1 row(s) retrieved. Database closed.

如果我们同时生成 sqexplain.out,会发现其中多了以下内容,表明外部 Directives 起了作用:

 External Directives in effect. DIRECTIVES FOLLOWED: AVOID_INDEX ( customer_t 201_107 ) DIRECTIVES NOT FOLLOWED:

需要注意的是,不要过分依使用这个特性,因为一旦打开外部 Directives 特性,一条语句执行前都需要查找相匹配的 Directives,尤其当 sysdirectives 中激活的记录不止一条时, 会导致数据库性能下降。


SQL Tracing

SQLTracing 是 IDS 版本 11 的新功能,用于追踪 SQl 执行的情况,以帮助诊断 SQL,包括:SQL 执行的时间、使用的资源情况、等待每一个资源的时间等。默认情况下 IDS 的 SQLTracing 功能是关闭的。

包括以下信息:

  The user ID of the user who ran the command The database session ID The name of the database The type of SQL statement The duration of the SQL statement execution The time this statement completed The text of the SQL statement or a function call list (also called stack trace) with the statement type, for example: procedure1() calls procedure2() calls procedure3() Statistics including the: 
–  Number of buffer reads and writes 
–  Number of page reads and writes 
–  Number of sorts and disk sorts 
–  Number of lock requests and waits 
–  Number of logical log records 
–  Number of index buffer reads 
–  Estimated number of rows 
–  Optimizer estimated cost 
–  Number of rows returned  isolation level.

管理 SQL Tracing

通过设置 ONCONFIG 文件参数

 SQLTRACE level=LOW,ntraces=2000,size=2,mode=global

其中:

  • level 可以是 LOW,MED,HIGH,
  • LOW 包括:statement statistics, statement text, and statement iterators.
  • MED 包括:all of the information included in low-level tracing, plus table names, the database name, and stored procedure stacks
  • HIGH 包括:all of the information included in low-level tracing, plus table names。
  • ntraces 表示追踪的最多 SQL 条数。
  • size 是指追踪每条 SQL 使用的内存大小,以 K 为单位。
  • Mode 可以是 global 或者 user,global 表示对所有用户打开 SQL 追踪功能,此模式下所有 SQL 都被追踪;user 表示以 user 模式打开 SQL 追踪,此模式下只有打开 SQL 追踪的 session 下的 SQL 才被追踪。

通过 Admin Command

以 global 模式打开 Tracing:

 EXECUTE FUNCTION task("set sql tracing on", 1000, 1,"high","global"); EXECUTE FUNCTION task("set sql tracing on", "global");

此模式下,所有用户的所有 SQL 都被追踪。

以 user 模式打开 Tracing:

 EXECUTE FUNCTION task("set sql tracing on", 1000, 1,"high","user"); EXECUTE FUNCTION task("set sql tracing on", "user");

此模式下,只有添加到追踪列表中用户的 SQL 才被追踪。

针对某些数据库打开 Tracing:

 EXECUTE FUNCTION task("set sql tracing database", ‘ demodb ’ );

针对某个 Session 打开 Tracing 功能:

 EXECUTE FUNCTION task("set sql user tracing on", session_id);

无论用户模式还是全局模式,此方式都能打开对当前 sessionSQL 的追踪。

针对某些用户打开 Tracing 功能:

第一步,先打开选择用户模式

 EXECUTE FUNCTION task("set sql tracing on", 1000, 1,"high", ’ user ’ );

第二步,把要追踪的用户添加到追踪列表

 EXECUTE FUNCTION task("set sql tracing user add", “informix"); 
……

关闭 Tracing。

关闭所有 ( 包括 global/user 模式 ) 的追踪。

 EXECUTE FUNCTION task(“set sql tracing off'”);

清除 user 模式下的追踪用户列表:

 EXECUTE FUNCTION task(“set sql tracing user clear”); EXECUTE FUNCTION task(“set sql tracing user remove”,”informix”);

清除被追踪的数据库:

 EXECUTE FUNCTION task("set sql tracing database clear");

注意: 在设置新的追踪方式前,最好先清除所有已设置的追踪标志,也就是先执行以下语句 z 组合以后,再设置新的追踪方式和目标。

 execute function sysadmin:task('set sql tracing off'); execute function sysadmin:task('set sql tracing user clear'); execute function sysadmin:task('set sql tracing database clear'); 
……
一个 SQLTracing 的例子
 [Informix@informix2 sqltuning]$echo “execute function sysadmin:task('set sql tracing on', 100,2,'high','global')” | dbaccess demodb[Informix@informix2 sqltuning]$ time echo "select * from customer c, orders o, cust_calls cc where c.customer_num = o.customer_num and cc.customer_num=c.customer_num and c.lname not like '%a';"| dbaccess demodb [Informix@informix2 sqltuning]$ time echo "select * from sysmaster:syssqltrace where sql_id=3"| dbaccess demodb Database selected. sql_id 11 sql_address 1275031644 sql_sid 41 sql_uid 503 sql_stmttype 2 sql_stmtname SELECT sql_finishtime 1268648703 sql_begintxtime 3870692 sql_runtime 0.007486995934 sql_pgreads 5 sql_bfreads 109 sql_rdcache 95.41284403670 sql_bfidxreads 0 sql_pgwrites 0 sql_bfwrites 0 sql_wrcache 0.00 sql_lockreq 81 sql_lockwaits 0 sql_lockwttime 0.00 sql_logspace 0 sql_sorttotal 0 sql_sortdisk 0 sql_sortmem 0 sql_executions 1 sql_totaltime 0.019677553892 sql_avgtime 0.019677553892 sql_maxtime 0.007486995934 sql_numiowaits 3 sql_avgiowaits 0.001834622424 sql_totaliowaits 0.005503867271 sql_rowspersec 1202.084264377 sql_estcost 11 sql_estrows 11 sql_actualrows 9 sql_sqlerror 0 sql_isamerror 0 sql_isollevel 2 sql_sqlmemory 23104 sql_numiterators 5 sql_database <None> sql_numtables 0 sql_tablelist None sql_statement select * from customer c, orders o, cust_calls cc where c.cus tomer_num = o.customer_num and cc.customer_num=c.customer_num and c.lname not like '%a'sql_stmtlen 148 sql_stmthash 755685204 sql_pdq 0 sql_num_hvars 0 sql_dbspartnum 1048969 1 row(s) retrieved.

通过命令行查看追踪结果:

 onstat – g his Statement history: Trace Level Low Trace Mode Global Number of traces 1000 Current Stmt ID 11 Trace Buffer size 1000 Duration of buffer 2455 Seconds Trace Flags 0x00001611 Control Block  0x4bff7018 Statement # 11: @ 0x4bff705c Database: 0x100189 Statement text: select * from customer c, orders o, cust_calls cc where c.customer_num = o.customer_num and cc.customer_num=c.customer_num and c.lname not like '%a'Iterator/Explain ================ ID Left Right Est Cost Est Rows Num Rows Partnum Type 3 0 0 4 7 7 1049056 Seq Scan 4 0 0 1 22 1 1049038 Index Scan 2 3 4 8 5 7 0 Nested Join 5 0 0 1 23 1 1049042 Index Scan 1 2 5 11 11 9 0 Nested Join

从上面的表格很容易可以得到如下图的执行计划:

图 5. 分析得出的执行计划示意
图 5. 分析得出的执行计划示意

Informix SQL 调整检查列表

在 select 语句中应指明需要访问的列名,而不要用 *

坏的方式:

 select * from customer;

好的方式:

 select customer_num, fname, lname from customer;

任何时候都应该只返回需要的列,避免不必要的资源消耗。

避免使用前置的通配符

坏的方式:

 select * from customer_t where fname like ‘ %f ’ ;

好的方式:

 select * from customer_t where fname like ‘ name% ’ ;

前置通配符将导致数据库不得不放弃使用索引,而使用全表扫描,如果有可能,应该尽量避免这种表达式。

使用 first、skip 关键词

如果只是想访问一个查询中符合条件的部分数据,则可以考虑使用 first,skip 关键词组合,在数据库服务器端实现分页,而不用访问全部数据。

例如:

如果每页需要 100 行数据,则:

取第一页的数据:

 select first 100 * from customer ;

取第二页数据:

 select skip 100 first 100 * from customer ;

取第三页数据:

 select skip 200 first 100 * from customer ; 
……
……

避免不必要的算术运算符

坏的方式:

 time echo "select count(*) from customer 
where customer_num *10/2 < 20000" | dbaccess demodb real 0m11.059s user 0m0.007s sys 0m0.008s

好的方式:

 time echo "select count(*) from customer where customer_num < 4000" | dbaccess demodb real 0m0.049s user 0m0.007s sys 0m0.009s

能提前完成的算术运算不要留给数据库,对于每一行都要进行的算术运算会导致不必要的性能问题。

避免不必要的函数运算

坏的方式:

 time echo "select count(*) from customer 
where substr(fname,1,1)='f' and customer_num < 300000"|dbaccess demodb real 0m1.511s user 0m0.006s sys 0m0.011s

好的方式:

 time echo "select count(*) from customer 
where fname like 'f%' and customer_num < 300000"|dbaccess demodb real 0m1.225s user 0m0.010s sys 0m0.007s

like,match 运算符要比内置的函数效率更高,函数调用需要占用更多的系统资源。必要时再使用。

使用 exists 替代 distinct

坏的方式:

 time echo "select distinct cu.customer_num, cu.fname from cust_calls cc, customer cu where cc.customer_num=cu.customer_num and cu.customer_num < 90000" | dbaccess demodb real 0m5.150s user 0m0.299s sys 0m0.401s

好的方式:

 time echo "select cu.customer_num, cu.fname from customer cu where cu.customer_num < 90000 and exists( select cc.customer_num from cust_calls cc where cc.customer_num=cu.customer_num) " | dbaccess demodb real 0m2.658s user 0m0.401s sys 0m0.294s

联合查询返回的内容有重复内容时,查询,返回和剔除重复记录都会占用不必要的系统资源,通过 exist 在 SQL 执行的初期就避免查询结果中包含重复记录,可以大幅提高效率。

使用 OR 替代 UNION

坏的方式:

 time echo "select customer_num, fname, lname from customer where customer_num<200000 and fname like 'f%' union select customer_num, fname, lname from customer where customer_num<200000 and fname like '%c'" | dbaccess demodb real 0m7.513s user 0m1.850s sys 0m0.814s

好的方式:

time echo "select customer_num, fname, lname 
from customer where customer_num<200000 
and (fname like 'f%' or fname like '%c')" | dbaccess demodb real 0m6.985s user 0m1.754s sys 0m0.927s

执行 Union 会涉及到两个数据集的合并操作,会占用较多的系统资源,可能情况下,尽量避免使用。一般情况下,一个 SQL 能完成的就用一个 SQL 完成。

使用 BETWEEN 替代 IN

坏的方式:

time echo "select customer_num,lname,fname from customer 
where customer_num 
in(10000,10001,10002,10003, …… 10222)"| dbaccess demodbreal 0m3.077s user 0m0.012s sys 0m0.017s

好的方式:

 time echo "select customer_num,lname,fname from customer where customer_num between 10000 and 10222"| dbaccess demodb real 0m1.711s user 0m0.017s sys 0m0.013s

正确使用 index scan 和 sequential scan

返回表的大部分数据时,使用顺序扫描更优。

返回表的少部分数据时,使用 index 扫描更优。

数据表之间做连接时,一般情况下要在连接列上建立索引。

避免某些不明智的 SQL

一个例子:

坏的方式: SQL-1

 select count(city) from customer where customer_num > all (select (customer_num) from customer_t)

好的方式:SQL-2

 select count(city) from customer where customer_num > (select max(customer_num) from customer_t)

对于 SQL-1:

 [Informix@informix2 sqltuning]$ time echo "set explain on; select count(city) from customer where customer_num > all (select (customer_num) from customer_t)" | dbaccess demodb Database selected. Explain set. (count) 4 1 row(s) retrieved. Database closed. real 2m7.820s user 0m0.007s sys 0m0.017s QUERY: (OPTIMIZATION TIMESTAMP: 01-07-2010 15:08:32) ------ select count(city) from customer where customer_num > all (select (customer_num) from customer_t) Estimated Cost: 1014292 Estimated # of Rows Returned: 1 1) informix.customer: SEQUENTIAL SCAN (Serial, fragments: ALL) Filters: informix.customer.customer_num > ALL <subquery> Subquery: --------- Estimated Cost: 3 Estimated # of Rows Returned: 1 1) informix.customer_t: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Aggregate) (Serial, fragments: ALL) Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 customer type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 4 2666674 10000028 05:08.62 1014293 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 4 05:08.62 Subquery statistics: -------------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 customer_t type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 1000000 1000000 1000000 00:15.77 3 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 1000000 00:18.78

对于 SQL-2:

 time echo "set explain on; select count(city) from customer where customer_num > (select max(customer_num) from customer_t)" | dbaccess demodb Database selected. Explain set. (count) 4 1 row(s) retrieved. Database closed. real 0m0.764s user 0m0.008s sys 0m0.010s QUERY: (OPTIMIZATION TIMESTAMP: 01-07-2010 15:11:33) ------ select count(city) from customer where customer_num > (select max(customer_num) from customer_t) Estimated Cost: 295661 Estimated # of Rows Returned: 1 1) informix.customer: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) Lower Index Filter: informix.customer.customer_num > <subquery> Subquery: --------- Estimated Cost: 3 Estimated # of Rows Returned: 1 1) informix.customer_t: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Aggregate) (Serial, fragments: ALL) Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 customer type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 4 2666674 4 00:00.49 295661 type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 4 00:00.49 Subquery statistics: -------------------- Table map : ---------------------------- Internal name Table name ---------------------------- type rows_prod est_rows rows_cons time ------------------------------------------------- group 1 1 0 00:00.23

总结

通过以上介绍,相信大家可以充分利用 Informix 提供的工具和特性,更加快速地定位 SQL 的性能问题,并且进行有效的调整。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 解决failed to lazily initialize a collection of role: XX ,could not initialize proxy - no Session

    报错:org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: XX, could not initialize proxy - no Session(未能惰性地初始化角色集合:XX,无法初始化代理-没有会话)解决方法: 将 @OneToMany(fetch = FetchType.LAZY, orphanRemov…...

    2024/4/24 23:21:47
  2. Vue-Cli4.x项目通过electron打包桌面应用程序

    发现网上的教程大部分都是vue2.x目录结构不太一样 还有就是将一些问题整合在一起傻瓜式教程 步骤一 下载electron的demo项目 electorn GitHub 下载demo electron-quick-start步骤二 运行demo项目 用你的ide打开demo项目 在项目根目录下 npm install npm start注意是根目录执行成…...

    2024/4/24 23:21:48
  3. Android异常——Fragment XXX not attached to Activity

    我的异常系列目录为:http://www.jianshu.com/p/cb10697226ef直接切入主题。出现这个问题后,我们定位到代码中的位置一般是getString或者getResources导致的!既然是Fragment出现的问题。我们直接定位到Fragment的源代码,检索错误的字符串,马上我们可以看到Fragment的getRes…...

    2024/5/4 11:37:15
  4. CSDN博客富文本编辑器正式上线公告

    CSDN博客富文本编辑器新版已经正式上线了,在此也特别感谢在之前的内测期间用户提供的意见及反馈,对于这些提供反馈意见及建议的用户,我们将会每人赠送价值 ¥89.00 元的CSDN下载频道季卡 一份,以下是本次的热心用户名单(奖品预计本周内安排发放,排名不分先后):@qq_3829…...

    2024/5/4 11:32:25
  5. hibernate_day05_JPA注解_一对多

    一对多注解@OneToMany作用建立一对多的关系映射属性targetEntityClass:指定多的方的类的字节码mappedBy:指定从表实体类中引用主表对象的名称,在哪方出现,哪方不维护外键cascade:指定要使用的级联操作fetch:指定是否采用延迟加载orphanRemoval:是否使用孤儿删除@ManyToOne…...

    2024/5/4 6:50:06
  6. 关于struct中的static变量

    先来看一段程序: #include <stdio.h> typedef struct with_static {int a;static const int b = 1;}with_static; int main() {struct with_static test1;struct with_static test2;test1.a = 1;printf("test1.a = %d/n",test1.a);printf("test1.b = %d/…...

    2024/4/14 21:13:43
  7. electron-vue跨平台桌面应用开发实战教程(七)——ffi调用C++(macOS平台)

    electron功能很强大,但是有一些跟操作系统底层交互的功能,electron无法实现,这个时候我们就可以调用原生来配合完成对应功能,本文主要讲解在macOS平台下,调用C++的dylib文件在开始之前我们要安装 1.node-gyp npm install node-gyp -g使用ffi-napi调用dll(c++) 1. 安装ff…...

    2024/4/28 9:52:15
  8. SQL Server 2005 中的商务智能和数据仓库

    微软发布了SQL Server 2005,对于微软与BI来说这是一个非常重要的版本,它完善了微软在BI方面的产品线。SQL Server 2005以及 Visual Studio .net2005的整合,有着庞大的开发用户,必将给BI领域的市场带来冲击。下面转载了一篇介绍性的文章共十部分,下面是第一部分,其他的请看…...

    2024/4/27 8:31:24
  9. electron+vue建立桌面级应用入门这一篇文章就够了

    写在前面 写这篇文章的时候已经是深夜十二点了,但是还是想写下来,因为我这个人有个毛病,就是当我发现一个新的好用的东西的时候常常会激动的睡不着觉,不记录下来根本睡不着,而且程序员晚睡不应该是标配吗?废话说了几句,说一下今天的主角,electron 做个自我介绍: 大家好…...

    2024/4/24 23:21:43
  10. 智能销售系统的订单采购和报表

    订单采购 组合关系 组合关系就是强聚合关系,最强级联,一方放弃维护 聚合就是双向的多对一,一对多 单据都是组合关系 保存的时候双方都能找到对象 //一方的配置 /**cascade = CascadeType.ALL:包含所有级联(增删改)orphanRemoval = true:孤儿删除mappedBy = "bill"…...

    2024/4/24 23:21:44
  11. 用VB访问SQL Server数据库技术详解

    本文讨论了Visual Basic应用程序访问SQL Server数据库的几种常用的方法,分别说明了每种方法的内部机理并给出了每种方法的一个简单的实例,最后比较了每种方法性能和优缺点。 一、引言   SQL Server是微软推出的中小型网络数据库系统,是目前最常用的数据库系统之一。随着SQ…...

    2024/5/3 23:46:16
  12. static修饰的函数作用与意义

    static修饰的函数叫做静态函数,静态函数有两种,根据其出现的地方来分类:如果这个静态函数出现在类里,那么它是一个静态成员函数; 静态成员函数的作用在于:调用这个函数不会访问或者修改任何对象(非static)数据成员。 其实很好理解,类的静态成员(变量和方…...

    2024/4/24 23:21:40
  13. [Android官方Demo系列] View间渐变

    简介:View间渐变效果图:代码分析:getResources().getInteger(android.R.integer.config_shortAnimTime);获取动画时间 :200 msprivate Class<? extends Activity> activityclass; 活动的变量定义/*alpha值取0%,则为纯透明。alpha值取100%,则为不透明。*/showView.…...

    2024/5/4 11:57:47
  14. Qt实战之开发CSDN下载助手 (1)

    这次实战,我们需要开发一款CSDN下载助手。它具备以下功能: 1) . 能够正常登录CSDN账户 2) . 能够根据用户提供的资源下载页面地址解析出真实地址 ( 当然啦, 你的账号积分要足够下载所需要积分) 3) . 能够在下载完毕后评价资源 ,然后获得返还积分。 4) . 相信你已经猜到了隐含…...

    2024/5/4 10:31:35
  15. electron桌面应用打开webview的方法

    const windowOptions = {title: demo,// titleBarStyle: hidden,width: 1440,height: 900,webPreferences: {devTools: true, //可禁用devTools:false,nodeIntegration: true,contextIsolation: true, //上下文隔离preload: path.join(__dirname, ./utils/preload.js), // webv…...

    2024/5/4 4:53:43
  16. Hibernate annotation

    @OneToOne 单向一对一模型@OneToOne 一对一 @JoinColumn用来指定生成的外键名字 例如:@JoinColumn(name="user_Id") @OneToOne注释指明实体A 与实体B 为一对一关系,@OneToOne注释六个属性:targetEntity、cascade、fetch、optional、orphanRemoval和mappedBy。 fe…...

    2024/4/24 23:21:36
  17. 另外的方法,得到drawable目录下的图片的ID

    flag.png 為例,可以用: int idFlag = getResources().getIdentifier( getPackageName() + ":drawable/flag", null, null); // 或是 int idFlag = getResources().getIdentifier( "flag", "drawable", getPackageName()); int …...

    2024/5/3 23:07:46
  18. 全能电子地图下载器 破解版 亲测可用

    『全能地图下载器』是一款地图、高程下载类GIS软件,支持将下载的地图、高程等数据进行多种专业格式转换,或发布为地图服务,旨在辅助用户提高工作效率,轻松构建自己的地图应用。可应用于学术科研、工程、规划、设计等工作,在测绘、地质、交通、电力、水利、农业、林业和旅游…...

    2024/5/4 10:05:35
  19. 局部对象,static局部对象,static全局对象

    为分清这些,我们先看一段代码:#include<iostream> static int global_sta = 1; //global_sta为静态全局对象 void print() {int non_local = 2; //non_local为局部对象,非静态的static sta_local = 3; //sta_local为静态局部对象 }非静态局部对象特点:在定义…...

    2024/4/24 23:21:33
  20. 理解SQL原理,写出高效的SQL语句

    转自 http://www.nowamagic.net/librarys/veda/detail/1502/我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,存储过程动不动就是上千行,如果数据量大,人员流动大,那么我们还能保证下一段时间系统还能流畅的运行吗?我们还能保…...

    2024/4/14 21:13:53

最新文章

  1. Vue计算属性 vs Methods

    在 Vue.js 中&#xff0c;计算属性&#xff08;computed properties&#xff09;和 methods 都是用于处理数据和逻辑的方式&#xff0c;但它们之间有一些重要的区别。 ### 计算属性&#xff08;Computed Properties&#xff09; 计算属性是基于它们的响应式依赖进行缓存的。只…...

    2024/5/6 22:13:25
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/6 9:38:23
  3. idea中 错误:找不到或无法加载主类

    很神奇的就是maven打包是正常的&#xff0c;本来也是好好的&#xff0c;突然启动就报错了&#xff0c;我百度了很急&#xff0c;没什么结果&#xff0c;找了公司6年工作经验的老员工&#xff0c;还是搞了好久&#xff0c;我站了好久也是没解决。后来我也是在想maven的jar包都能…...

    2024/5/5 14:22:32
  4. 第三章:fs 模块

    fs 模块 文章目录 fs 模块一、文件写入1-1.writeFile 异步写入1-2.writeFileSync 同步写入1-3.appendFile / appendFileSync 追加写入1-4.createWriteStream 流式写入1-5.写入文件的场景 二、文件读取2-1.readFile 异步读取2-2.readFileSync 同步读取2-3.createReadStream 流式…...

    2024/5/5 8:39:23
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/4 23:54:56
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/4 23:54:56
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/6 9:21:00
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/4 23:55:16
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/4 23:55:06
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57