请求有关优化SQL查询的提示

时间:2017-04-23 22:09:13

标签: sql optimization indexing

我有一个看起来相当简单的SQL查询。但是,它在生产中表现不佳。任何提高绩效的建议都将受到赞赏。

    SELECT  DISTINCT CUSTOMERS.CUST_ID,
       CUSTOMERS.FNAME,
       CUSTOMERS.LNAME,
       CUSTOMERS.CURR_STAT,
       CUSTOMERS.CREATE_TIME,
       CUSTOMERS.ROUTE_NBR,
    FROM CUSTOMERS
    INNER JOIN 
       INVS
    ON 
       CUSTOMERS.CUST_ID = INVS.CUST_ID
    WHERE
       CUSTOMERS.ROUTE_NBR = 'A10' AND
       ( 
          CUSTOMERS.LAST_UPD_DT >= ? OR 
          CUSTOMERS.CURR_STAT IN ( 'PRE' , 'POST' , 'REV')
       ) AND
       CUSTOMERS.CURR_STAT NOT IN ( 'START' , 'END' , 'REJ') AND
       (
          INVS.INV_CODE = 'AVL' OR 
          INVS.INV_CODE = 'ONORD'
       )

以下列的CUSTOMERS表上有一个索引:

  1. ROUTE_NBR
  2. CUST_ID
  3. CREATE_TIME
  4. CURR_STAT
  5. 如果索引包含LAST_UPD_DT列而不是CREATE_TIME列来反映谓词,它会产生显着差异吗?可以做出任何其他改进吗?谢谢。

2 个答案:

答案 0 :(得分:1)

由于您只从CUSTOMERS表中获取列,我建议使用EXISTS操作来删除DISTINCT操作。它将是:

SELECT CUSTOMERS.CUST_ID,
       CUSTOMERS.FNAME,
       CUSTOMERS.LNAME,
       CUSTOMERS.CURR_STAT,
       CUSTOMERS.CREATE_TIME,
       CUSTOMERS.ROUTE_NBR,
  FROM CUSTOMERS
 WHERE CUSTOMERS.ROUTE_NBR = 'A10' 
   AND (CUSTOMERS.LAST_UPD_DT >= ? OR 
        CUSTOMERS.CURR_STAT IN ( 'PRE' , 'POST' , 'REV')) 
   AND CUSTOMERS.CURR_STAT NOT IN ( 'START' , 'END' , 'REJ') 
   AND EXISTS (SELECT 1 
                 FROM INVS
                WHERE INVS.CUST_ID = CUSTOMERS.CUST_ID
                  AND INVS.INV_CODE IN ('AVL', 'ONORD')
              )

同时添加当前查询的解释计划肯定会有所帮助。对于你的问题if the index included the LAST_UPD_DT column instead of the CREATE_TIME column to reflect the predicates?很可能是的。

但您知道的确切方法是获取实际创建/更改索引的解释计划,并将其与新的解释计划进行比较。

答案 1 :(得分:1)

我同意Jorge关于删除distinct并使用exists

SELECT c.*  -- or whatever
FROM CUSTOMERS c
WHERE c.ROUTE_NBR = 'A10' AND
      (c.LAST_UPD_DT >= ? OR 
       c.CURR_STAT IN ( 'PRE' , 'POST' , 'REV')
      ) AND
      c.CURR_STAT NOT IN ( 'START' , 'END' , 'REJ') AND
      EXISTS (SELECT 1
              FROM INVS
              WHERE C.CUST_ID = INVS.CUST_ID AND INVS.INV_CODE IN ('AVL', 'ONORD')

   );

然后,对于此查询,您需要INVS(CUST_ID, INV_CODE)CUSTOMERS(ROUTE_NBR, CURR_STAT, LAST_UPD_DT, CUST_ID)上的索引。