以更有效的方式表达oracle查询

时间:2018-06-13 15:16:52

标签: sql oracle

我有下面的oracle查询,它正在获取结果并以完美的方式显示结果,但请建议我能以更有效的方式编写以下查询

SELECT DISTINCT PSNETWORKID
FROM JGH
INNER JOIN IDF
ON IDF.PSIDFFIID         = JGH.PSNETWORKID
WHERE (JGH.zzACQUIRERID IN
  (SELECT DISTINCT pstdftermid FROM YUI WHERE pstdftermownid =111111
  )
OR zzACQUIRERID = 111111);

3 个答案:

答案 0 :(得分:0)

这似乎是您的查询:

select distinct PSNETWORKID 
from JGH INNER JOIN
     IDF 
     on IDF.PSIDFFIID = JGH.PSNETWORKID 
where JGH.zzACQUIRERID in (select pstdftermid 
                           from YUI
                           where pstdftermownid = 111111
                          ) or
      zzACQUIRERID = 111111; 

首先,select distinct通常是一个坏主意。让我假设它在其中一个表中是唯一的 - 比如JFH。然后,我会这样做:

select jgh.PSNETWORKID 
from JGH 
where exists (select 1
              from IDF
              where IDF.PSIDFFIID = JGH.PSNETWORKID
             ) and
      (exists (select 1
               from YUI
               where JGH.zzACQUIRERID = YUI.pstdftermid and YUI.pstdftermownid = 111111
             ) or
       jgh.zzACQUIRERID = 111111
      ); 

然后,我会建议IDF(PSIDFFIID)YUI(pstdftermid, pstdftermownid)上的索引。

答案 1 :(得分:0)

“高效”是指简洁或更快的运行时间?通常你想使用EXIST而不是IN。

SELECT distinct PSNETWORKID  
  FROM JGH 
 INNER 
  JOIN IDF 
    ON IDF.PSIDFFIID= JGH.PSNETWORKID 
 WHERE EXISTS  
          ( SELECT 1 
              FROM (SELECT pstdftermid conditionField
                      FROM YUI 
                     UNION ALL
                    SELECT 111111 AS conditionField
                      FROM dual
                   ) TMP
             WHERE JGH.zzACQUIRERID = TMP.conditionField
          );

答案 2 :(得分:0)

这是在Oracle 11.2.0.2.0上测试的。请注意,您的版本在此处是相关的,因为旧版本的某些非常好的建议可能与较新版本无关。

这是我使用您的查询和生成的数据执行的执行计划

--------------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     1 |    39 |       |   437   (1)| 00:00:06 |
|   1 |  HASH UNIQUE         |             |     1 |    39 |       |   437   (1)| 00:00:06 |
|*  2 |   FILTER             |             |       |       |       |            |          |
|*  3 |    HASH JOIN         |             |   108K|  4142K|  2656K|   436   (1)| 00:00:06 |
|   4 |     TABLE ACCESS FULL| IDF         |   108K|  1380K|       |    46   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL| JGH         |   109K|  2786K|       |    62   (2)| 00:00:01 |
|*  6 |    INDEX RANGE SCAN  | PSTDFTERMID |   725 | 18850 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("JGH"."ZZACQUIRERID"=111111 OR  EXISTS (SELECT 0 FROM "YUI" "YUI" 
              WHERE "PSTDFTERMOWNID"=111111 AND "PSTDFTERMID"=:B1))
   3 - access("IDF"."PSIDFFIID"="JGH"."PSNETWORKID")
   6 - access("PSTDFTERMID"=:B1 AND "PSTDFTERMOWNID"=111111)

因此,一个可能建议使您的查询更“有效”可能是重新排序OR谓词并将子查询放在第二位以避免执行子查询(如果谓词{{1 }} 是真的。 但如果您在上面的第2行看到zzACQUIRERID = 111111,则 由Oracle为您完成

接下来的建议是使用filter而不是EXISTS运算符。如果您查看IN的第二部分,则情况也是如此 - 查询重写并使用filter

所以最重要的部分是(并且我认为这与你的查询相关,如果它永远不会结束 - 你没有提到)在EXISTS上有索引。这为您提供了第6行的索引访问。

如果你在这个地方看到像

那样的东西
YUI(pstdftermid, pstdftermownid)

这会导致执行效率低下,为每个|* 8 | TABLE ACCESS FULL | YUI | 10000 | 100 | 10000 |00:00:01.82 | 131K| | | | 8 - filter(("PSTDFTERMID"=:B1 AND "PSTDFTERMOWNID"=111111)) 密钥进行一次全表扫描

所以我的建议是在第一步检查执行计划,并确保有提到的索引。

仅当您希望强制 Oracle采用不同的执行计划时才重写查询,而不是基于过去版本中的最佳实践