那些年,我们处理过的SQL问题

简介:

分析一次SQL并行执行的产生过程

1、并行引起的灾祸

一大早,某网省兄弟告诉我,数据库会话执行的SQL开启了并行,导致负载很高,会话也高,查了半天,没找到具体原因,也不知道该如何解决?

对于他的问题,我直接回应了:这还不清楚吗?常见原因无非有以下两个:

第一:对象开启了并行(包括索引和表)

第二:SQL语句里面使用了PARALLEL的HINTS

现场兄弟说,都查了并没有上面的情况,听到他的回答,我首先对他查询的方式持怀疑态度的,没有设置并行度,也没有加HINTS,执行的SQL怎么会并行执行呢?带着这个疑问,我叫现场兄弟把查询结果一一截图给我,如下(文中案例都是事后补充):

25dc338be531b4560846cf19f578ab5ac3f2eedf

看到结果后我一时也有点摸不着头脑,怎么回事?遇到问题我总是告诉自己要冷静,不急。

2、层层推进,分析问题

是不是什么参数控制了?

SQL> show parameter parallel

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

fast_start_parallel_rollback string LOW

parallel_adaptive_multi_user boolean TRUE

parallel_automatic_tuning boolean FALSE

parallel_degree_limit string CPU

parallel_degree_policy string MANUAL

parallel_execution_message_size integer 16384

parallel_force_local boolean FALSE

parallel_instance_group string

parallel_io_cap_enabled boolean FALSE

parallel_max_servers integer 320

parallel_min_percent integer 0

parallel_min_servers integer 0

parallel_min_time_threshold string AUTO

parallel_server boolean FALSE

parallel_server_instances integer 1

parallel_servers_target integer 128

parallel_threads_per_cpu integer 2

recovery_parallelism integer 0

没有发现可疑参数。

至此,表面排查的结果已经解决不了这个问题了,于是我让现场找了一条正在并行的SQL ,手动执行,并收集一个10053事件trace,看看是否能有新发现。脚本如下

2ef70378ea48491662d29aeb929dcb0da7582cbe

很快现场提供了TRACE FILE文件给我,我优先看参数列表。

这时,我发现一个可疑的参数:parallel_query_default_dop = 16

bdc2cb42d2d5c20273435ba0c2863d614c3300cb

找到mos上关于该参数的相关信息,是一个默认并行度的参数,该参数值的算法如下:

DEFAULT DOP = cpu_count * parallel_threads_per_cpu* cluster_database_instances

我立刻问现场同事,执行的SQL在活动会话中体现的是不是16个并行进程。现场同事答复我,观察到的基本就是。至此问题明朗起来了,执行的SQL使用了默认并行度执行,受参数parallel_query_default_dop控制。既然是默认的并行度,那也应该需要设置(如果不设置,默认是1)。于是我把前期的查询验证对象并行度是否开启的SQL改造了下,具体如下(文中案例都是事后补充)

8b1839aaf26a2b9c8af9b77e14fe2cf6abac702f

查询结果截图发出来,我就开心了,这里明显有一个设置了并行度为DEFAULT(如果我们不设置就是1)的表和索引。然后确认了他们正是正在运行的sql中的对象。

3、问题解决

既然设置了默认并行度,那么只需要取消默认并行度即可,即执行如下SQL

--针对表

alter table table_name noparalle;

--针对索引

Alter index index_name noparallel;

于是我叫现场把对象并行度修改为1,再次执行该SQL,发现并行消失了,数据库恢复了正常。

问题虽然解决了,但还有一个疑问没有解开,什么情况下会设置的并行度为DEFUALT呢?正常创建索引和表都是1。

4、如何设置并行度为default

通过实践发现如下2种方式可以实现并行度设置为DEFAULT。

1、创建表的时候指定:

a73e7717f042cd4d61fb232641e4402dfbbd73c4

2、创建表之后可以修改

6996882a3c6fb9d6ae60084089b6c86f57d54b6e

小结:该问题解决第一个是思路 ,第二个是基本功要扎实。

DB升级之后,DBLINK引起执行计划异常分析

背景如下:某网省采集中间库从10.2.0.4升级到11.2.0.4(备注升级不是在老的机器上面直接升级,而是在新机器上面采用安装迁移的方式)

升级完第二天现场找到我,说以前同步档案数据的接口功能目前都运行非常慢(数据接口同步的方式采用的DBLINK),有时甚至无法正常运行完,影响档案资料的同步,看来已经很严重了。

关键字:DB升级从10G升级到11G

我以前遇到过相关案例,觉得可能是升级带来的执行计划变化引起的。于是告知现场尝试修改优化器参数即optimizer_features_enable改成10.2.0.4,可以在线改,立刻生效,脚本如下:

alter system set optimizer_features_enable='10.2.0.4' scope=both;

修改完成后,重新在执行同步档案资料接口的任务看是否正常。

现场经过一番测试之后,问题没有解决,看来老的经验无法解决该问题。

好,接下来我们做了以下模拟测试:

该SQL的文本如下:

INSERT INTO EPCT.C_CUST_ADDR@EPEXDB

(CUST_ID,

CUST_ADDR,

PROVINCE_CODE,

CITY_CODE,

COUNTY_CODE,

STREET_CODE,

VILLAGE_CODE,

ROAD_CODE,

COMMUNITY_CODE,

PLATE_NO,

TYPE_CODE,

POSTALCODE,

CA_ID,

APP_NO)

SELECT A2.CUST_ID,

A2.CUST_ADDR,

A2.PROVINCE_CODE,

A2.CITY_CODE,

A2.COUNTY_CODE,

A2.STREET_CODE,

A2.VILLAGE_CODE,

A2.ROAD_CODE,

A2.COMMUNITY_CODE,

A2.PLATE_NO,

A2.TYPE_CODE,

A2.POSTALCODE,

A2.CA_ID,

''

FROM SGPM.C_CUST_ADDR A2

WHERE A2.CUST_ID=ANY

(SELECTA3.CUST_ID

FROM SGPM.C_CONS A5,

SGPM.R_CP_CONS_RELA A4,

SGPM.C_CUST A3

WHERE A4.CONS_ID=A5.CONS_ID

AND A4.CP_NO=:B1

ANDA5.CUST_ID=A3.CUST_ID);

可以看到是用到DBLINK从A数据库到B数据库的插入语句,这个SQL发起端在A数据库,也就是程序部署在A数据库中,而该SQL实际执行端在B数据库。虽然是往B数据库插入数据,但是会派生一个查询SQL到A数据库取数。

针对INSERT INTO remote_table@dblink select * from local_table这种SQL执行端都会在远端,不是本地,无法使用HINTS driving_site指定执行端。

2、然后会在A数据库确认一下是否派生一个SQL,并且找到该SQLID

3、现场提供SQLID之后,我们可以获取该sql执行的相关信息:

select *from table(dbms_xplan.display_cursor('1ar4us01aj0hu',null,'ADVANCED'));

66b837d1ee8db2af7804f4f3eb57b8cbadb84893

红框里出现的字样引起了我的注意,眼尖的DBA应该很快会发现其中的猫腻。

对的,这里调用了一个内部函数。这个函数的说明如下:

The internal Oracle function SYS_OP_C2C performs conversion

from one character set to another character set C(haracterSet)2C(haracterSet).

字符集之间的转换。OK ,看到这里我问现场,新旧两套B数据库中字符集是什么? A数据库字符集又是什么?

现场答复如下:

老的B数据库字符集是utf-8

新的B数据库字符集是zhs16gbk

而A数据库字符集是utf-8

这个也就说明了,迁移到新采集中间库之后性能急剧下降的原因找到了。

那么解决方式有如下2种方式:

第一修改字符集,保证源目标字符集一致。

第二创建函数索引。

域索引导致提交报告的展开讨论

域索引导致提交报错

最近处理了一个网省的问题,现场反馈提交报错 ,报错如下:

COMMIT;

ERROR at line 1:

ORA-00604: error occurred at recursive SQL level 1

ORA-20000: Oracle Text error:

DRG-50610: internal error: drexdsync

DRG-50857: oracle error in drekrtd (reselect rowid row locator)

ORA-00942: table or view does not exist

ORA-06512: at "CTXSYS.SYNCRN", line 1

ORA-06512: at line 1

看到这个错误,我们获取到如下信息

1、这个是关于域索引的报错

2、这个是递归SQL导致的报错

3、这个是报表或者视图不存在(最大可能是权限 或者可能就是真不存在)

见到这个错误,首先找现场核实下权限问题,包括操作用户的权限

核查结果并没有异常。

进一步分析:

1、查询域索引信息

Select * from ctxsys.ctx_indexes

2、创建一个域索引会自动创建属性为BASIC_STORAGE的四个二级表对象和一个索引对象出来

BASIC_STORAGE has the following attributes:

i_table_clause Parameter clause for dr$<indexname>$I table creation.

The I table is the index data table.

k_table_clause Parameter clause for dr$<indexname>$K table creation.

The K table is the keymap table.

r_table_clause Parameter clause for dr$<indexname>$R table creation.

The R table is the rowid table.

n_table_clause Parameter clause for dr$<indexname>$N table creation.

The N table is the negative list table.

i_index_clause Parameter clause for dr$<indexname>$X index creation.

大家可以在自己的环境中使用如下SQL查询

Select owner,object_name,object_type,secondary,status

from dba_objects

where owner ='SGPM'

and object_name like 'DR$INDEX_NAME$%' --INDEX_NAME修改为你实际的名称

现场查询结果为空,说明域索引已经不存在了,从而导致提交报错,也就是递归执行域索引的SQL报错。

问题定位到,解决问题的办法很容易:

重建域索引即可。

我这里给出的例子指出了域索引的实际存储表空间位置,目的就是可控,如果不指定就是创建用户所在默认的表空间。

begin

--创建词法分析

--ctx_ddl.create_preference ('chinese_lexer', 'chinese_lexer');

--存储参数

ctx_ddl.create_preference('t1_stor','BASIC_STORAGE');

ctx_ddl.set_attribute('t1_stor','I_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','I_INDEX_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','K_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','R_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','N_TABLE_CLAUSE','tablespace TEST');

end;

--创建域索引 指定storage参数和lexer词法分析器参数

create index idx1_t1 on t1(object_name) indextype is ctxsys.context parameters ('lexer chinese_lexer storage t1_stor');

--同步域索引数据:(该操作有风险业务低估操作)

查询确认域索引是否需要同步

select u.username, i.idx_name

from ctxsys.dr$index i, dba_users u

where u.user_id=i.idx_owner#

and idx_id in (select pnd_cid from ctxsys.dr$pending);

exec ctx_ddl.sync_index('IDX1_T1');

--优化域索引数据(该操作有风险业务低估操作)

exec ctx_ddl.optimize_index ('IDX1_T1', 'full');

原文发布时间为:2018-11-13
本文作者:郑林松
本文来自云栖社区合作伙伴“ 数据和云”,了解相关信息可以关注“ 数据和云”。
相关文章
|
1月前
|
SQL 关系型数据库 MySQL
|
3月前
|
SQL 数据库 索引
八、SQL-Limite
八、SQL-Limite
24 0
|
SQL 存储 数据库
SQL 能做什么?
SQL 能做什么?
86 0
|
SQL 数据挖掘 Python
sql8&10&11&12,3+1
sql8&10&11&12,3+1
sql8&10&11&12,3+1
|
SQL 数据库
了解SQL
了解SQL
93 0
|
SQL Oracle 关系型数据库
一个需求的三种实现(sql)
一个需求的三种实现(sql)
一个需求的三种实现(sql)
|
SQL 存储 数据库