今天因为程序设计漏洞,把一张表得数据给truncate掉了,然后再重跑的过程中发现有一条sql再pl/sql工具执行很快(1秒内),程序中却需要200-300秒。
sql如下:
MERGE INTO t_qt_second t1
USING (select d.sn_no ,c.stair_org_id ,c.stair_org_name , a.assetpro_name , a.org_no , a.assetpro_no
from t_org_sn a, t_device b, t_org_inf c , t_qt_second d
where a.csn = b.dev_sn
and a.org_no = c.idorganization
and b.dev_sn = d.sn_no) t2
on (t1.sn_no = t2.sn_no)
WHEN MATCHED THEN
UPDATE SET t1.stair_org_id = t2.stair_org_id , t1.stair_org_name = t2.stair_org_name ,
t1.assetpro_name = t2.assetpro_name,t1.assetpro_no = t2.assetpro_no , t1.org_no = t2.org_no;
执行时间如图:
如图,sql是一条批量修改sql。再面向搜索引擎编程过程中发现一个关键字,PreparedStatement 。这位大佬说
一开始怀疑是语句使用UPER函数导致的,但是把语句修改为不使用函数也一样慢。。怀疑是使用了PreparedStatement 参数需要动态绑定问题,于是将PreparedStatement 改为Statement ,执行却很快
然而因为我们系统的封装太厚了,没法将PreparedStatement 改为 Statement。于是我在想虽然我整个sql没有参数绑定,但是我给他强行加一个固定参数绑定会不会有效果!于是sql就变成了这样
MERGE INTO t_qt_second t1
USING (select d.sn_no ,c.stair_org_id ,c.stair_org_name , a.assetpro_name , a.org_no , a.assetpro_no
from t_org_sn a, t_device b, t_org_inf c , t_qt_second d
where a.csn = b.dev_sn
and a.org_no = c.idorganization
and b.dev_sn = d.sn_no
*and 1 = ${variable}*) t2
on (t1.sn_no = t2.sn_no)
WHEN MATCHED THEN
UPDATE SET t1.stair_org_id = t2.stair_org_id , t1.stair_org_name = t2.stair_org_name ,
t1.assetpro_name = t2.assetpro_name,t1.assetpro_no = t2.assetpro_no , t1.org_no = t2.org_no
可以看到在t2表 条件的最后我加了一个 and 1 = ${variable},其中variable变量在程序里面设置的是 1,然后再放到服务器上重跑一下。
!!!!!
再来看下执行时间!!!
终于舒服了~~~~~~
题外话:
这个应该和我们系统的破框架有关系,这个框架会存储程序运行过程中(变量、sql查询等一系列和数据有关系的操作)的数据以节点树的形式存储在树上(具体是什么树也没有研究过,框架封装太厚,看不到)。
以下是我对这破框架的猜想:
所以存在每一条sql运行过程中,会去扫描整个树中有没有某个节点是sql的绑定参数。才导致这种没有参数绑定的sql在程序上执行特别慢。
另外
如果有同样问题的朋友,并且你们是使用的mybatis,可以检查下自己动态绑定的参数 和 数据库中对应字段的 类型是不是一致。比如代码中给的类型是string,但是数据库中该字段是int,这样也可能会导致在工具上执行快,程序中很慢的情况。