【问题标题】:Requesting tips in optimizing a SQL query请求优化 SQL 查询的提示
【发布时间】:2026-02-20 05:25:01
【问题描述】:

我有一个看起来相当简单的 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

如果索引包含 LAST_UPD_DT 列而不是 CREATE_TIME 列来反映谓词,是否会产生显着差异?还有什么可以改进的吗?谢谢。

【问题讨论】:

  • 是所有四列的索引还是每列一个索引?
  • 什么数据库?表格的行数是多少?
  • 还有其他CURR_STAT 不在您在查询中使用的那 6 个吗?
  • @JorgeCampos 有一个由这四列组成的索引。是的,CURR_STAT 还有其他几个值。
  • @ULick 数据库是 db2。大约有 400 万条客户记录和大约 200 万条库存记录。

标签: sql optimization indexing


【解决方案1】:

由于您只从CUSTOMERS 表中获取列,我建议使用EXISTSoperation 来删除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? 很可能是的。

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

【讨论】:

  • 谢谢你,豪尔赫。我将按照您的建议修改查询,更改索引,并从 DBA 获得解释计划。感谢您的投入!
【解决方案2】:

我同意 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) 上的索引。

【讨论】:

  • 感谢您的意见,戈登!谢谢。