【问题标题】:Same Query, Different Peformance相同的查询,不同的性能
【发布时间】:2017-03-30 14:54:50
【问题描述】:

有一个查询需要两分钟以上。该查询的结果是 960000 行。 所以我使用提示。然后只需 30 秒。所以我在 mybatis 中应用了查询并运行应用程序。但该查询需要两分钟多的时间。所以我在日志中复制了查询并粘贴了本地开发人员。并执行查询。但它只需要 30 秒。 我不知道…………

环境:spring、mybatis、oracle

SELECT * 
FROM (
    SELECT /*+ USE_HASH(a b c) */ ROW_NUMBER() OVER(ORDER BY A.TRANS_DT DESC, A.TRANS_TM DESC) AS RNUM                    
          ,A.PAY_METHOD
          ,B.BRAND_NM  
          ,A.I_MID                                
          ,C.TRANS_DT  
          ,C.TRANS_TM  
          ,C.TRANS_DT || C.TRANS_TM AS TRANS_DTM   
          ,C.VACCT_VALID_DT                        
          ,C.VACCT_VALID_TM                        
          ,C.VACCT_VALID_DT||C.VACCT_VALID_TM AS VACCT_VALID_DTM 
          ,NVL(C.DEPOSIT_DT, ' ') DEPOSIT_DT                     
          ,NVL(C.DEPOSIT_TM, ' ') DEPOSIT_TM                     
          ,NVL(C.DEPOSIT_DT, ' ')||NVL(C.DEPOSIT_TM, ' ') AS DEPOSIT_DTM    
          ,NVL(C.DEPOSIT_AMT, 0) AS AMT                                     
          ,NVL(A.AMT, 0) AS INPUT_AMT                                       
          ,A.BANK_CD                                                        
          ,IONPAY.UF_GET_BANK_NAME(A.BANK_CD) AS BANK_CD_NM                 
          ,C.VACCT_NO                                                  
          ,A.BILLING_NM                                           
          ,A.REFERENCE_NO                                    
          ,A.TXID                                        
          ,A.STATUS         
          ,NVL(A.STATUS, ' ') AS INPUT_STATUS    
          ,IONPAY.UF_GET_TRANS_VACCT_STATUS_NAME(C.STATUS) AS INPUT_STATUS_NAME
          ,C.STATUS AS TRANS_STATUS  
          ,IONPAY.UF_GET_TRANS_VACCT_STA_NAME_2(C.STATUS, C.MATCH_CL, C.VACCT_VALID_DT, C.VACCT_VALID_TM) AS STATUS_NAME 
          ,A.ACQU_STATUS                 
          ,A.CANCEL_DT||A.CANCEL_TM AS REVERSAL_DATE 
          ,NVL((SELECT DESC2
                    FROM TB_CODE
                    WHERE CODE_CL = 'CHNL'
                      AND CODE1 = C.BANK_CD
                      AND CODE2 = C.CHANNEL_TYPE), ' ') AS channel
    FROM TB_TRANS_HISTORY A, TB_BO_MER_MGMT B, TB_VACCT_TRANS C
    WHERE A.I_MID = B.I_MID
      AND A.TXID = C.TXID
      AND A.I_MID = C.I_MID
      AND B.I_MID = C.I_MID
      AND A.PAY_METHOD IN ('02')
      AND A.TRANS_DT BETWEEN '20161016' AND '20161116' 
      AND A.TRANS_DT||A.TRANS_TM BETWEEN '2016101600%3A0000' AND '2016111624%3A0000'     
      AND B.TAX_NO != 'NICEPAY' 
      AND C.SIMULATION_FLG = '0' 
      AND C.STATUS IN ('0', '1', '2', '3', '4') 
) TBL
WHERE RNUM BETWEEN 210000 AND 220000

【问题讨论】:

  • EXPLAIN PLAN 在任何情况下都是您的朋友。查找表扫描和丢失的索引。这是一个非常复杂的查询,嵌入了很多业务逻辑。
  • 在 sql 工具中执行查询或使用 mybatis 执行查询是完全不同的事情......查询可能仍然一样快,但 mybatis 也会创建对象并且它会减慢速度。所以你基本上是在比较不同的事情查询执行和查询执行+对象创建。
  • 对不起.. 只是执行时间。我检查了数据库服务器中查询的执行时间。
  • 如果a.trans_dt 是DATE 数据类型,那么AND A.TRANS_DT BETWEEN '20161016' AND '20161116' 应该是AND A.TRANS_DT BETWEEN to_date('20161016', 'yyyymmdd') AND to_date('20161116', 'yyyymmdd')。另外,AND A.TRANS_DT||A.TRANS_TM BETWEEN '2016101600%3A0000' AND '2016111624%3A0000' 就是and a.trans_tm = '%3A0000'
  • @boniest - 这仍然不能解释时间上的差异(因为所有版本都有错误的比较);但也许如果 OP 修复了您指出的内容,则差异将在一个 1.5 秒和另一个 6 秒之间,他/她将能够继续做其他事情。 :-)

标签: spring oracle mybatis difference hint


【解决方案1】:

我已经遇到过这样的情况:时间差不是在SQL查询执行上,而是在获取结果上。

Oracle JDBC 驱动程序默认提取大小为 10,这意味着 ResultSet 以 10 行乘以 10 行的形式提供,当有 100 万条记录时,这会导致大量往返数据库。必须增加 Fetch 大小。

使用 PostgreSql,默认获取大小是无限的:ResultSet 被提供整个结果(或直到 OutOfMemory)。可能需要减小 Fetch 大小。

在Mybatis中指定fetch size值:

在 XML select 语句中使用 fetchSize 属性:

<select id="listItems" fetchSize="300">SELECT ...</select>

或者在注解中使用 fetchSize 选项:

@Select("SELECT ...")
@Options(fetchSize=300)

200-500 范围内的值通常是一个很好的折衷方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多