SQL 语句优化

linxi246 2014-08-12 10:09:58
SELECT B.LGTD,B.LTTD,A.STCD,B.STNM,B.ADDVCD,'ZZ' STTP,B.FRGRD,A.TM,A.Z VALUE FROM  A, B 
WHERE (NOT EXISTS(SELECT * FROM C WHERE STCD=A.STCD AND TM>A.TM AND TM>to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd')))
AND A.TM>to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd') AND A.STCD=B.STCD AND B.STTP IN('ZZ','ZQ','PP','DD') AND B.LGTD IS NOT NULL
AND B.LTTD IS NOT NULL AND ADDVCD IS NOT NULL;


现在有上面的一条SQL语句想进行优化,因为对于SQL不是太熟,只是听说子查询速度比较慢,所以想通过 join 的方式来处理,后来请同事写了一个,但效率并没有提高多少,所以想请大家帮忙看看,感谢~~

SELECT D.LGTD,D.LTTD,C.STCD,D.STNM,D.ADDVCD,'ZZ' STTP,D.FRGRD,C.TM,C.Z VAL
FROM
(select stcd,max(tm) maxtm from A
where tm > to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd')
group by stcd
) B
inner join C ON B.STCD = C.STCD
left join D ON C.STCD = D.STCD
where B.maxtm = C.TM and D.STTP IN('ZZ','ZQ','PP','DD') AND D.LGTD IS NOT NULL
AND D.LTTD IS NOT NULL AND D.ADDVCD IS NOT NULL;


这个是同事写的SQL~~
...全文
126 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
bw555 2014-08-12
  • 打赏
  • 举报
回复
时间条件忘写了,呵呵
(select STCD,MAX(TM) AS TM,
max(Z)keep(dense_rank last order by TM) AS Z
FROM ST_RIVER_R
WHERE TM>to_date('2011-08-11','yyyy-mm-dd')
    AND TM<=to_date('2011-08-14','yyyy-mm-dd')
GROUP BY STCD
) Z
bw555 2014-08-12
  • 打赏
  • 举报
回复
耗时最多的应该是not exists 部分,考虑使用分析函数
(SELECT * FROM ST_RIVER_R A
    WHERE (NOT EXISTS(SELECT * FROM ST_RIVER_R C WHERE STCD=A.STCD AND TM>A.TM
                 AND TM>to_date('2011-08-11','yyyy-mm-dd')
                 AND TM<=to_date('2011-08-14','yyyy-mm-dd'))) 
    AND A.TM>to_date('2011-08-11','yyyy-mm-dd')
    AND A.TM<=to_date('2011-08-14','yyyy-mm-dd')) Z
改为
(select STCD,MAX(TM) AS TM,
max(Z)keep(dense_rank last order by TM) AS Z
FROM ST_RIVER_R
GROUP BY STCD
) Z
试一下
linxi246 2014-08-12
  • 打赏
  • 举报
回复
引用 6 楼 bw555 的回复:
提供下执行计划吧,针对性的优化可能效果更好点
SELECT T.LGTD,T.LTTD,Z.STCD,T.STNM,T.ADDVCD,'ZZ' STTP,T.FRGRD,Z.TM,Z.Z VALUE
FROM 
    (SELECT * FROM ST_RIVER_R A
    WHERE (NOT EXISTS(SELECT * FROM ST_RIVER_R C WHERE STCD=A.STCD AND TM>A.TM
                 AND TM>to_date('2011-08-11','yyyy-mm-dd')
                 AND TM<=to_date('2011-08-14','yyyy-mm-dd'))) 
    AND A.TM>to_date('2011-08-11','yyyy-mm-dd')
    AND A.TM<=to_date('2011-08-14','yyyy-mm-dd')) Z,
    (SELECT * FROM ST_STBPRP_B B 
    WHERE 
    B.STTP IN('ZZ','ZQ','PP','DD')
    AND B.LGTD IS NOT NULL 
    AND B.LTTD IS NOT NULL
    AND B.ADDVCD IS NOT NULL)  T
WHERE Z.STCD=T.STCD;
执行计划
Plan hash value: 2587998097
 
---------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             | 10561 |  2031K|  3614   (2)| 00:00:44 |
|*  1 |  HASH JOIN RIGHT ANTI         |             | 10561 |  2031K|  3614   (2)| 00:00:44 |
|*  2 |   TABLE ACCESS FULL           | ST_RIVER_R  | 11117 |   293K|  3060   (2)| 00:00:37 |
|   3 |   NESTED LOOPS                |             |       |       |            |          |
|   4 |    NESTED LOOPS               |             | 11117 |  1845K|   553   (0)| 00:00:07 |
|*  5 |     TABLE ACCESS FULL         | ST_STBPRP_B |   540 | 70200 |    13   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN          | STCD_TM1    |    42 |       |     1   (0)| 00:00:01 |
|   7 |    TABLE ACCESS BY INDEX ROWID| ST_RIVER_R  |    21 |   840 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("STCD"="A"."STCD")
       filter("TM">"A"."TM")
   2 - filter("TM">TO_DATE(' 2011-08-11 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
              "TM"<=TO_DATE(' 2011-08-14 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
   5 - filter("B"."LGTD" IS NOT NULL AND "B"."LTTD" IS NOT NULL AND "B"."ADDVCD" IS 
              NOT NULL AND ("B"."STTP"='DD' OR "B"."STTP"='PP' OR "B"."STTP"='ZQ' OR 
              "B"."STTP"='ZZ'))
   6 - access("A"."STCD"="B"."STCD" AND "A"."TM">TO_DATE(' 2011-08-11 00:00:00', 
              'syyyy-mm-dd hh24:mi:ss') AND "A"."TM"<=TO_DATE(' 2011-08-14 00:00:00', 'syyyy-mm-dd 
              hh24:mi:ss'))
 
Note
-----
   - dynamic sampling used for this statement (level=2)

   Statistics
-----------------------------------------------------------
               6  CPU used by this session
               8  CPU used when call started
             128  DB time
               1  enqueue releases
               1  enqueue requests
             189  non-idle wait count
             113  non-idle wait time
               6  opened cursors cumulative
               1  opened cursors current
             178  physical read total IO requests
             162  physical read total multi block requests
               1  pinned cursors current
              10  recursive calls
               1  recursive cpu usage
           14997  session logical reads
          131072  session pga memory
          458416  session uga memory
             113  user I/O wait time
               6  user calls
bw555 2014-08-12
  • 打赏
  • 举报
回复
提供下执行计划吧,针对性的优化可能效果更好点
linxi246 2014-08-12
  • 打赏
  • 举报
回复
引用 4 楼 linxi246 的回复:
[quote=引用 2 楼 bw555 的回复:]
先试下这个
SELECT B.LGTD,B.LTTD,A.STCD,B.STNM,B.ADDVCD,'ZZ' STTP,B.FRGRD,A.TM,A.Z VALUE
FROM
(SELECT * FROM A
WHERE (NOT EXISTS(SELECT * FROM C WHERE STCD=A.STCD AND TM>A.TM
AND TM>to_date('2011-08-11','yyyy-mm-dd')
AND TM<=to_date('2011-08-14','yyyy-mm-dd')))
AND A.TM>to_date('2011-08-11','yyyy-mm-dd')
AND A.TM<=to_date('2011-08-14','yyyy-mm-dd')) A
(SELECT * FROM B
WHERE
AND B.STTP IN('ZZ','ZQ','PP','DD')
AND B.LGTD IS NOT NULL
AND B.LTTD IS NOT NULL
AND ADDVCD IS NOT NULL) B
WHERE A.STCD=B.STCD

如果还慢的话,就需要看执行计划针对性的优化


好的,我试试~[/quote]


时间依然是1秒以上,没有多少提高~~
linxi246 2014-08-12
  • 打赏
  • 举报
回复
引用 2 楼 bw555 的回复:
先试下这个
SELECT B.LGTD,B.LTTD,A.STCD,B.STNM,B.ADDVCD,'ZZ' STTP,B.FRGRD,A.TM,A.Z VALUE
FROM 
	(SELECT * FROM A
	WHERE (NOT EXISTS(SELECT * FROM C WHERE STCD=A.STCD AND TM>A.TM
                 AND TM>to_date('2011-08-11','yyyy-mm-dd')
                 AND TM<=to_date('2011-08-14','yyyy-mm-dd'))) 
	AND A.TM>to_date('2011-08-11','yyyy-mm-dd')
	AND A.TM<=to_date('2011-08-14','yyyy-mm-dd')) A
	(SELECT * FROM B 
	WHERE 
	AND B.STTP IN('ZZ','ZQ','PP','DD')
	AND B.LGTD IS NOT NULL 
	AND B.LTTD IS NOT NULL
	AND ADDVCD IS NOT NULL) B
WHERE A.STCD=B.STCD
如果还慢的话,就需要看执行计划针对性的优化
好的,我试试~
linxi246 2014-08-12
  • 打赏
  • 举报
回复
SELECT B.LGTD,B.LTTD,A.STCD,B.STNM,B.ADDVCD,'ZZ' STTP,B.FRGRD,A.TM,A.Z VALUE 
FROM ST_RIVER_R A,ST_STBPRP_B B
WHERE
(NOT EXISTS(SELECT * FROM ST_RIVER_R WHERE STCD=A.STCD AND TM>A.TM AND TM>to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd')))
AND A.TM>to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd') AND A.STCD=B.STCD
AND B.STTP IN('ZZ','ZQ','PP','DD') AND B.LGTD IS NOT NULL
AND B.LTTD IS NOT NULL AND B.ADDVCD IS NOT NULL;


SELECT D.LGTD,D.LTTD,C.STCD,D.STNM,D.ADDVCD,'ZZ' STTP,D.FRGRD,C.TM,C.Z VAL
FROM
(select stcd,max(tm) maxtm from ST_RIVER_R
where tm > to_date('2011-08-11','yyyy-mm-dd') AND TM<=to_date('2011-08-14','yyyy-mm-dd')
group by stcd
) B
inner join ST_RIVER_R C ON B.STCD = C.STCD
left join ST_STBPRP_B D ON C.STCD = D.STCD
where B.maxtm = C.TM and D.STTP IN('ZZ','ZQ','PP','DD') AND D.LGTD IS NOT NULL
AND D.LTTD IS NOT NULL AND D.ADDVCD IS NOT NULL;


这个是有表名的SQL

ST_STBPRP_B 表结构截图


ST_RIVER_R 表结构截图


bw555 2014-08-12
  • 打赏
  • 举报
回复
先试下这个
SELECT B.LGTD,B.LTTD,A.STCD,B.STNM,B.ADDVCD,'ZZ' STTP,B.FRGRD,A.TM,A.Z VALUE
FROM 
	(SELECT * FROM A
	WHERE (NOT EXISTS(SELECT * FROM C WHERE STCD=A.STCD AND TM>A.TM
                 AND TM>to_date('2011-08-11','yyyy-mm-dd')
                 AND TM<=to_date('2011-08-14','yyyy-mm-dd'))) 
	AND A.TM>to_date('2011-08-11','yyyy-mm-dd')
	AND A.TM<=to_date('2011-08-14','yyyy-mm-dd')) A
	(SELECT * FROM B 
	WHERE 
	AND B.STTP IN('ZZ','ZQ','PP','DD')
	AND B.LGTD IS NOT NULL 
	AND B.LTTD IS NOT NULL
	AND ADDVCD IS NOT NULL) B
WHERE A.STCD=B.STCD
如果还慢的话,就需要看执行计划针对性的优化
小灰狼W 2014-08-12
  • 打赏
  • 举报
回复
请提供执行计划、涉及表和字段的相关信息 另外,如果原表名因为保密关系需要隐藏,请用统一的名字代替。你这里明显ABCD都对不上
linxi246 2014-08-12
  • 打赏
  • 举报
回复
引用 10 楼 wildwave 的回复:
ST_RIVER_R做全表扫描的成本较高 在这个表上建组合索引(STCD,TM,Z),代替原有的(stcd,tm) 语句的话,将原来那条和楼上的写法来比较一下
由于是业务数据库,只有查询的权限,所以更改表结构应该做不到~~
linxi246 2014-08-12
  • 打赏
  • 举报
回复
引用 9 楼 bw555 的回复:
时间条件忘写了,呵呵
(select STCD,MAX(TM) AS TM,
max(Z)keep(dense_rank last order by TM) AS Z
FROM ST_RIVER_R
WHERE TM>to_date('2011-08-11','yyyy-mm-dd')
AND TM<=to_date('2011-08-14','yyyy-mm-dd')
GROUP BY STCD
) Z


非常感谢,效率有很大的提升......

小灰狼W 2014-08-12
  • 打赏
  • 举报
回复
ST_RIVER_R做全表扫描的成本较高 在这个表上建组合索引(STCD,TM,Z),代替原有的(stcd,tm) 语句的话,将原来那条和楼上的写法来比较一下
更优更快 人工智能自动SQL优化----------http://www.sina.com.cn 2001/12/12 17:48 中国电脑教育报文/SQL爱好者  所谓SQL,就是指Structured Query Language(结构化查询语言),它是目前使用最广泛的数据库语言,用来和数据库打交道,从数据库中得到用户需要的数据。但是要想熟练使用SQL语句,也不是一件简单的事,有些语句使用起来也比较麻烦。如果我们对SQL语句进行优化,那么用户使用起来 就会方便许多。  简单来说,SQL语句优化就是将性能低下的SQL语句转换成达到同样目的的性能优异的SQL语句。人工智能自动SQL优化就是使用人工智能技术,自动对SQL语句进行重写,找到性能最好的等效SQL语句。  人工智能自动SQL 优化  随着人工智能技术的发展和在数据库优化领域应用的深入,在20世纪90年代末终于出现了突破性的进展——人工智能自动SQL优化。目前在商用数据库领域LECCO TechnologyLimited(灵高公司)拥有该技术并提供使用该技术的自动优化产品——LECCO SQL Expert,其支持Oracle、Sybase、MS SQLServer和IBMDB2数据库平台。该产品针对数据库应用的开发和维护阶段提供了几个特别的模块:SQL语法优化器、PL/SQL集成化开发调试环境(IDE)、扫描器、数据库监视器等。图1 人工智能自动SQL优化示意图  其核心模块之一“SQL语法优化器”的工作原理大致如下(如图1):  一条源SQL语句输入→“人工智能反馈式搜索引擎”对输入的SQL语句结合检测到的数据库结构和索引进行重写,产生N条等效的SQL语句输出→产生的N条等效SQL语句再送入“人工智能反馈式搜索引擎”进行重写,直至无法产生新的输出或搜索限额满→对 输出的SQL语句进行过滤,选出具有不同执行计划的SQL语句(即不同的执行效率)→对得到的SQL语句进行批量测试,找出性能最好的SQL语句。图2 优化前的SQL语句  自动优化实例  假设我们从源代码中抽取出这条SQL语句(如图2):  SELECTCOUNT(*)FROMEMPLOY-EE WHEREEXISTS(SELECT'X'FROM DEPARTMENTswheresEMP_DEPT=DPT_IDAND DPT_NAME LIKE'AC%')AND EMP_IDIN(SELECT SAL_EMP_IDFROM EMP_SAL_HISTB WHERESAL_SALARY>70000)   按“优化”按钮后,经过十几秒,SQL Expert就完成了优化的过程,从优化细节中可以看到,它在十几秒的时间内重写产生了2267条等价的SQL语句,其中136条SQL语句有不同的执行计划(如图3)。图3 优化结果  接下来我们可以对自动重写产生的136条具有不同执行计划的SQL语句进行批运行测试,以选出性能最佳的等效SQL语句。按下“批运行”按钮,在“终止条件”页选择“最佳运行时间SQL语句”(如图4),按“确定”。图4 测试条件  经过几分钟的测试运行后,我们可以发现SQL124的运行时间和反应时间最短。运行速度约有22.75倍的提升(源SQL语句运行时间为2.73秒,SQL124运行时间为0.12秒,如图5)。图5 测试结果  我们把SQL124放入源代码中,结束一条SQL语句优化工作。从上例可以看到,LECCO SQL Expert的自动重写技术使原来需要几小时才能完成的SQL语句优化工作,缩减到几分钟之内就可以完成。数据库管理员和开发人员可以从繁重的SQL语句优化工作中解脱出来。  边做边学式训练  LECCO SQL Expert不仅能够找到最佳的SQL语句,而且提供的“边做边学式训练”还能够教会开发人员和数据库管理员如何写出性能最好的SQL语句。LECCO SQL Expert的“SQL比较器”可以标明源SQL和待选SQL之间的不同之处。LECCO SQL Expert详尽的上下文敏感帮助系统可以指出执行计划的深层含义。图6 源语句SQL124的比较  以上面优化的结果为例,为了查看源SQL语句SQL124在写法上的不同,我们可以按下“比较器”按钮,对SQL124和源SQL语句进行比较。如果选择“双向比较”复选框,“SQL比较器”可以将两条互相间的不同之处以蓝色表示。当然,你也可以从 源语句和重写后的SQL语句中任选两条进行比较(如图6)。  从比较的结果可以看到,重写得到的SQL124把第一个Exists改写成了In;在字段DPT_ID上进行了合并空字符串的操作以诱导数据库先执行子查询中的(SELECTDPT_ID||'FROMDEPART-MENTWH

3,491

社区成员

发帖
与我相关
我的任务
社区描述
Oracle 高级技术相关讨论专区
社区管理员
  • 高级技术社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧