一条insert语句导致的性能问题分析(一)

今天早上开发找我看一个问题,说他们通过程序连接去查一个表的数据的时候,只查到了8条记录,这个情况着实比较反常,因为从业务上的数据情况来说,不可能只有8条。
但是开发没有太多的权限做线上环境的数据检查,就让我帮忙看一下。
语句大概是下面这样的形式。
select count(*) from TEST_VIP_LOG t where t.flag in(2,3) and insert_time >= to_date('2016-03-10','YYYY-MM-DD') and insert_time< to_date('2016-03-17','YYYY-MM-DD')
简单运行之后,发现返回的结果是2万多条记录。
当然我这边查询的结果还是有一定的可靠性的。所以开发的这个问题就自然落到了我的头上,为什么他们查看的数据只有8条,而我这边的数据却有2万多条,这个问题听起来确实有些蹊跷,但是都是事出有因,简单了解了一下事情的来龙去脉之后,原来他们是在早上八点程序自动连接去做的查询,我查询的时候已经到了快10点,这个时间点里,一切皆有可能,但是为什么短时间内会有这么大的数据变化呢,于是我查看了数据库的负载情况,发现在八点左右确实有一些DB time的提升,查看sql方面的变化,也确实发现有一个job在运行,而运行的过程中会涉及这个表TEST_VIP_LOG的数据变更。看起来问题似乎是有了一些眉目。但是当我查看锁的情况时,整个人都不好了。
$ sh showlock.sh
Current Locks
-------------
SID_SERIAL   ORACLE_USERN OBJECT_NAME               LOGON_TIME           SEC_WAIT OSUSER     MACHINE      PROGRAM              STAT  STATUS     LOCK_ MODE_HELD
------------ ------------ ------------------------- ------------------- --------- ---------- ------------ -------------------- ---------- ---------- ----- ----------
2655,14247   SYS          TEST_VIP_LOG              2016-03-16 01:03:25         0 oracle     statg2.cyou. oracle@statg2.cyou.c WAITING        ACTIVE     DML   Row-X (SX)
可以看到有一个session还在active状态,而且相关的表正是test_vip_log,而且这个session是在凌晨1点登陆的,一直到了早上十点多还在运行。也就间接意味着运行了近10个小时。
关联了一下对应的session执行的语句,发现是一条insert语句,竟然运行了近10个小时。
$ sh showsessql.sh 2655,14247
SQL_ID                         SQL_TEXT
------------------------------ ------------------------------------------------------------
d1zs82wnrs52u                  INSERT INTO TEST_VIP_LOG(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIM
                               E,OLD_RANK,SIGN,STATUS,TAG,OLD_SCORE) SELECT A.CN,A.GRADE,A.
                               RANK,A.SCORE,DECODE(SIGN(A.RANK-(NVL(B.RANK,-1))),1,2,-1,3,0
                               ,1), SYSDATE,(NVL(B.RANK,-1)),B.SIGN,B.FLAG,B.TAG,B.SCORE FR
                               OM ( SELECT * FROM TEST_VIP_NEW MINUS SELECT * FROM TEST_VIP_NEW_BAK
                               ) A LEFT JOIN TEST_VIP_NEW_BAK B ON A.CN=B.CN                                                                                           
然后就开始想这个语句是在几个月以前有一个需求变更,里面有两个表TEST_VIP_NEW和TEST_VIP_NEW_BAK做一些关联,然后把数据插入TEST_VIP_LOG,这个关联看起来还是比较奇怪的。
我们来简单看一看。
insert into TEST_vip_log(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIME,OLD_RANK,sign,stat
us,TAG,OLD_SCORE)
        select  a.cn,a.GRADE,a.RANK,a.SCORE,DECODE(sign(a.rank-(NVL(b.rank,-1))),1,2,-1
,3,0,1),
        sysdate,(NVL(b.rank,-1)),b.sign,b.flag,b.tag,b.score
        from
        (
             select * from TEST_vip_new minus select * from TEST_vip_new_bak
        ) a left join TEST_vip_new_bak b
        on a.cn=b.cn ;
首先test_vip_new会和test_vip_new_bak做一个minus操作,会以test_vip_new为基准匹配,然后得到的结果集再和test_vip_new_bak继续匹配,左连接匹配。
总体来看这个映射关系没有任何意义啊。可以做一个简单的测试来说明。两个表存在一个字段id,然后做匹配
SQL> create table a (id number);
Table created.

SQL> create table b (id number);
Table created.

SQL> insert into a values(1);
1 row created.

SQL> insert into a values(2);
1 row created.

SQL> insert into b values(1);
1 row created.

SQL> select * from a minus select * from b;
        ID
----------
         2
minus之后得到的结果是id=2的记录,然后再和表b映射,那么这种映射关系得到的结果是下面的形式。
SQL> select *from (select * from a minus select * from b) a left join b on a.id=b.id;
        ID         ID
---------- ----------
         2
感觉这种表连接方式就是多余的,因为minus之后的结果,表b中肯定是没有匹配的值,再一次关联也实在是浪费。
然后回到原本的sql语句。
xxxx  (select * from TEST_vip_new minus select * from TEST_vip_new_bak
        ) a left join TEST_vip_new_bak b
        on a.cn=b.cn
这个表test_vip_new_bak反复关联,这个表的数据是怎么得来的呢,原来在job开始运行的时候就会重新初始化这个表的数据
execute immediate 'truncate table TEST_vip_new_bak';
insert /*+ append*/ into TEST_vip_new_bak select * from TEST_vip_new;
COMMIT;
按照目前的分析思路,可见test_vip_new里面的数据和test_vip_new_bak中的数据差别很小,为什么不直接去增量的数据呢。带着疑问感觉好像找到了问题的关键,然后把开发的同学叫上来一起讨论一番,其实对于我来说是比较好奇为什么会写出那样的表关联,当时是出于什么特别的考虑。

时间: 2024-09-20 06:02:19

一条insert语句导致的性能问题分析(一)的相关文章

一条insert语句导致的性能问题分析(二)

今天对之前描述的问题一条insert语句导致的性能问题分析(一) 进行了进一步的补充. 有一条insert语句的主要性能瓶颈在于insert子句中的查询语句,查询中的主要资源消耗在于对两个表进行了多次关联 语句主要的结构如下: insert into xxxxx   (select * from TEST_vip_new minus select * from TEST_vip_new_bak         ) a left join TEST_vip_new_bak b         on

一条sql语句导致的数据库宕机问题及分析

之前分享过一篇博文,是一条sql语句"导致"的数据库宕机,上次是另有原因,这次真碰到一个案例,而且是在重要的环境上,希望大家引以为戒. 数据库是基于Linux64的版本,版本是11.2.0.2.0,已经打了最新的psu. 数据库的访问用户数大约在1000左右,当时查看服务器的cpu已经是100%了,有大约10个进程都是cpu 100%,数据库逻辑读也是超高,一秒钟大约是接近百兆的情况,sga是12G,已用了sga的自动管理(sga_target=0), 查看内存组件时发现buffer_

使用一条INSERT语句完成多表插入

这是一条颠覆常规的插入方法,一条INSERT语句可以完成向多张表的插入任务.小小地展示一下这种插入方法. 1.创建表T并初始化测试数据,此表作为数据源. sec@ora10g> create table t (x number(10), y varchar2(10)); sec@ora10g> insert into t values (1,'a'); sec@ora10g> insert into t values (2,'b'); sec@ora10g> insert into

MySQL中insert语句没有响应的问题分析(r11笔记第21天)

 今天开发的一个同学问我一个MySQL的问题,说在测试数据库中执行一条Insert语句之后很久没有响应.我一看语句是一个很常规的insert into xxx values形式的语句.看起来有些不太合乎常理啊,我对这类问题立马来了兴趣,准备好好看看到底是什么原因.  向开发同学了解了环境之后,我登录到服务端,首先查看是否可能是磁盘空间不足导致的问题.结果df -h的结果显示,空间还绰绰有余. 使用show proceslist查看线程情况. 可以看到大量的线程是Waiting for table

MySQL · 源码分析 · 一条insert语句的执行过程

本文只分析了insert语句执行的主路径,和路径上部分关键函数,很多细节没有深入,留给读者继续分析 create table t1(id int); insert into t1 values(1) 略过建立连接,从 mysql_parse() 开始分析 void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state) { /* ...... */ /* 检查query_cache,如果结果存在于c

sql中LEFT JOIN拆分成多条SQL语句 提高sql性能

本文讲解如何把一条带有一个或多个left join或right join的sql语句拆分成多条sql语句.MySQL进行连表查询效率是很低的,特别是数据很大,而且并发量很高的情况,索引都无法解决问题,最好的办法就是把sql语句拆分成多条单表查询的sql. 我们公司电商网站现在要做网站服务化,用java做中间件,PHP调用java接口获取数据,数据表也进行了拆分,分库,要求不使用连表查询,有连表查询的sql语句想办法拆分多条sql语句,然后统一使用java接口. 这样做的目的一是为了网站服务化做调

一条sql语句“导致”的数据库宕机问题及分析

最近测试环境需要做一些变更,把测试环境切分成两套环境,存储空间也需要压缩压缩和整理. unix组的人已经开始做空间划分了,然后我们需要在此基础上重建一套环境. 有些数据文件使用空间不大,所以准备压缩一下. 用了下面的sql语句,结果跑了十几秒中就抛了下面的错误. SQL> set linesize 200 SQL> col name for a40 SQL> col resizecmd for a80 SQL> select a.file#,a.name,a.bytes/1024/

一条sql语句的建议调优分析

前几天开发的同事问我一个sql的问题,目前在测试环境中发现这条sql语句执行时间很长,希望我们能够给一些建议,能够尽快做一些改进.sql语句类似下面的形式.SELECT /*+ INDEX(ACCOUNT,ACCOUNT_PK)INDEX(ACCOUNT_EXT ACCOUNT_EXT_PK) */ ACCOUNT.ACCOUNT_ID, ACCOUNT.BE, ACCOUNT.CUSTOMER_NO, ACCOUNT.AR_BALANCE, ACCOUNT_EXT.CYCLE_CODE, AC

merge语句导致的性能问题紧急优化

晚上正在休息的时候,突然收到一封报警邮件. 报警内容: CPU utilization is too high ------------------------------------ 报警级别: PROBLEM ------------------------------------ 监控项目: CPU idle time:59.11 % ------------------------------------ 这个报警信息已经非常明确,CPU使用率很紧张了.这台服务器上运行着Oracle和M