【问题标题】:SQL query taking 35 minsSQL 查询耗时 35 分钟
【发布时间】:2014-08-18 16:19:53
【问题描述】:

如何提高以下查询的性能?目前需要 35 分钟。

-- Select    
SELECT   
    RPT_FT_MD_FLOWS.FECDATA,  RPT_FT_MC_CONTR.L2V,  
    RPT_FT_MD_FLOWS.CODCONT, SUM(RPT_FT_MD_FLOWS.IMPMOCMP) 
FROM  
    RPT_FT_MD_FLOWS,
    RPT_FT_MC_CONTR     
WHERE    
    -- joins
    RPT_FT_MD_FLOWS.IDGRUEMP = RPT_FT_MC_CONTR.IDGRUEMP AND 
    RPT_FT_MD_FLOWS.FECDATA  = RPT_FT_MC_CONTR.FECDATA AND 
    RPT_FT_MD_FLOWS.CODCONT  = RPT_FT_MC_CONTR.CODCONT AND 
    RPT_FT_MD_FLOWS.IDEMPR   = RPT_FT_MC_CONTR.IDEMPR AND 
    RPT_FT_MD_FLOWS.IDCENT   = RPT_FT_MC_CONTR.IDCENT AND 
    RPT_FT_MD_FLOWS.CODPROD  = RPT_FT_MC_CONTR.CODPROD AND 
    RPT_FT_MD_FLOWS.IDCONTR  = RPT_FT_MC_CONTR.IDCONTR AND 
    RPT_FT_MD_FLOWS.IDSCONTR = RPT_FT_MC_CONTR.IDSCONTR AND
    -- filters
    RPT_FT_MD_FLOWS.FECDATA  = '31-May-2014' AND
    RPT_FT_MD_FLOWS.IDGRUEMP = '0022' AND
    RPT_FT_MD_FLOWS.ACUMTEMP = 'MTH' AND  
    RPT_FT_MD_FLOWS.IDESCENA = '01' AND
    RPT_FT_MD_FLOWS.CODCONT='CCPP' 
--group by 
GROUP BY 
    RPT_FT_MD_FLOWS.FECDATA,
    RPT_FT_MC_CONTR.L2V,
    RPT_FT_MD_FLOWS.CODCONT
  • RPT_FT_MC_CONTR:3900 万行
  • RPT_FT_MD_FLOWS:1.45 亿行

这里是解释命令的结果:

解释命令

Execution Plan
----------------------------------------------------------
Plan hash value: 2459895390

------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name            | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                 |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |        |      |            |
|   1 |  PX COORDINATOR                 |                 |       |       |            |          |       |       |        |      |            |
|   2 |   PX SEND QC (RANDOM)           | :TQ10002        |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |  Q1,02 | P->S | QC (RAND)  |
|   3 |    HASH GROUP BY                |                 |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |  Q1,02 | PCWP |            |
|   4 |     PX RECEIVE                  |                 |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |  Q1,02 | PCWP |            |
|   5 |      PX SEND HASH               | :TQ10001        |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |  Q1,01 | P->P | HASH       |
|   6 |       HASH GROUP BY             |                 |   268 | 29212 | 30846   (8)| 00:09:16 |       |       |  Q1,01 | PCWP |            |
|*  7 |        HASH JOIN                |                 |    39M|  4127M| 30586   (7)| 00:09:11 |       |       |  Q1,01 | PCWP |            |
|   8 |         PX BLOCK ITERATOR       |                 |    39M|  1893M| 10659   (4)| 00:03:12 |     1 |    16 |  Q1,01 | PCWC |            |
|*  9 |          TABLE ACCESS FULL      | RPT_FT_MC_CONTR |    39M|  1893M| 10659   (4)| 00:03:12 |   833 |   848 |  Q1,01 | PCWP |            |
|  10 |         PX RECEIVE              |                 |   145M|  8184M| 19806   (9)| 00:05:57 |       |       |  Q1,01 | PCWP |            |
|  11 |          PX SEND BROADCAST LOCAL| :TQ10000        |   145M|  8184M| 19806   (9)| 00:05:57 |       |       |  Q1,00 | P->P | BCST LOCAL |
|  12 |           PX BLOCK ITERATOR     |                 |   145M|  8184M| 19806   (9)| 00:05:57 |    66 |    66 |  Q1,00 | PCWC |            |
|* 13 |            TABLE ACCESS FULL    | RPT_FT_MD_FLOWS |   145M|  8184M| 19806   (9)| 00:05:57 |    66 |    66 |  Q1,00 | PCWP |            |
------------------------------------------------------------------------------------------------------------------------------------------------

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

   7 - access("RPT_FT_MD_FLOWS"."CODCONT"="RPT_FT_MC_CONTR"."CODCONT" AND "RPT_FT_MD_FLOWS"."FECDATA"="RPT_FT_MC_CONTR"."FECDATA" AND
              "RPT_FT_MD_FLOWS"."IDGRUEMP"="RPT_FT_MC_CONTR"."IDGRUEMP" AND "RPT_FT_MD_FLOWS"."IDEMPR"="RPT_FT_MC_CONTR"."IDEMPR" AND
              "RPT_FT_MD_FLOWS"."IDCENT"="RPT_FT_MC_CONTR"."IDCENT" AND "RPT_FT_MD_FLOWS"."CODPROD"="RPT_FT_MC_CONTR"."CODPROD" AND
              "RPT_FT_MD_FLOWS"."IDCONTR"="RPT_FT_MC_CONTR"."IDCONTR" AND "RPT_FT_MD_FLOWS"."IDSCONTR"="RPT_FT_MC_CONTR"."IDSCONTR")
   9 - filter("RPT_FT_MC_CONTR"."IDGRUEMP"='0022' AND "RPT_FT_MC_CONTR"."FECDATA"=TO_DATE(' 2014-05-31 00:00:00', 'syyyy-mm-dd
              hh24:mi:ss'))
  13 - filter("RPT_FT_MD_FLOWS"."IDESCENA"='01' AND "RPT_FT_MD_FLOWS"."FECDATA"=TO_DATE(' 2014-05-31 00:00:00', 'syyyy-mm-dd
              hh24:mi:ss') AND "RPT_FT_MD_FLOWS"."IDGRUEMP"='0022' AND "RPT_FT_MD_FLOWS"."ACUMTEMP"='MTH')

【问题讨论】:

  • 感谢 Chris 的编辑,现在看起来很清晰
  • 您的连接语法是ancient,您需要修复它。
  • 为什么要在这么多条件下加入 2 个表?
  • 这是业务报告要求
  • @nkalis 如果只有两张桌子,您只需加入将桌子放在一起的项目。加入表后,您无需添加更多谓词。他们有什么共同的ID吗?你也有任何索引,因为它似乎没有被使用。

标签: sql query-performance


【解决方案1】:

好吧,出于某种原因,我将尝试帮助解决这个问题。因此,让我们从清理它开始,以便它可以使用。首先,我们将从删除ancient join syntax 开始。我们还将添加一些别名。别名是当您给标题一个昵称时,您可以在所有地方引用该昵称,这样我们就不会在任何地方使用重复的表名来混淆代码。这给了我们类似的东西。

SELECT   
    F.FECDATA,  
    C.L2V,  
    F.CODCONT, 
    SUM(F.IMPMOCMP) 
FROM RPT_FT_MD_FLOWS as F
INNER JOIN RPT_FT_MC_CONTR as C
    ON F.IDGRUEMP = C.IDGRUEMP  
    AND F.FECDATA  = C.FECDATA  
    AND F.CODCONT  = C.CODCONT  
    AND F.IDEMPR   = C.IDEMPR  
    AND F.IDCENT   = C.IDCENT  
    AND F.CODPROD  = C.CODPROD  
    AND F.IDCONTR  = C.IDCONTR  
    AND F.IDSCONTR = C.IDSCONTR 
WHERE F.FECDATA  = '31-May-2014' 
    AND F.IDGRUEMP = '0022' 
    AND F.ACUMTEMP = 'MTH'   
    AND F.IDESCENA = '01' 
    AND F.CODCONT='CCPP' 
GROUP BY 
    F.FECDATA,
    C.L2V,
    F.CODCONT

让我们从这些连接谓词开始。我知道您声称这些是业务规则,但是将两个表连接在一起真的有必要吗?如果是这样,那么您的表结构是固定的。有 9 个连接谓词将 2 个表放在一起应该是零理由。它们是否都真正增加了查询的选择性?如果这都是真正需要的,那么您的表结构需要修复。

接下来,您的表似乎没有利用任何索引。如果您还没有这个,您应该在这些表上添加某种聚集索引以方便搜索。

您可能还想在此表中添加一些其他索引,以帮助减少为获得结果而必须扫描/查找的许多数据量。您的查询没有理由必须连接所有 1.84 亿行才能返回 268 行。

【讨论】:

  • 这里真正的解决方案是修复表格的设计。不需要在 8 列上进行连接。
  • @Kermit 我非常怀疑现在是否还有。
  • 嗨,Kermit,您能否详细说明一下这个问题 - 这里真正的解决方案是修复表格的设计,我会将其放在解决方案中
  • 我不认为这是一个可以简单地在 SO 问题中解决的主题。
【解决方案2】:

您可能想从头开始重写您的查询

  1. 在表之间使用普通连接 (INNER),并且只包含一个 where 子句,其中应用了不是连接的过滤器。
  2. 查看数据库的规范化程度,如果规范化程度良好,您应该能够优化索引和统计信息以提高查询性能。
  3. 看看可能派上用场的分区之类的东西。
  4. 检查数据页的碎片化程度,如果这会导致问题,请予以修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-07
    • 2018-05-09
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多