这个oracle查询可以再调整一下吗?

时间:2014-11-26 17:55:02

标签: sql performance oracle10g

我试图在不创建任何索引的情况下尽可能地降低此查询的成本。

这是原始查询,费用为599:

SELECT DISTINCT OL.PRODUCT_ID
FROM ORDERS O JOIN ORDER_LINES OL ON (O.ORDER_ID = OL.ORDER_ID)
              JOIN PRODUCTS P     ON (OL.PRODUCT_ID = P.PRODUCT_ID)
              JOIN CUSTOMERS C    ON (C.CUSTOMER_ID = O.CUSTOMER_ID)
WHERE C.CUSTOMER_ID = 474871
      OR UPPER(C.FIRST_NAME) = 'EDGAR';

这是我迄今为止所做的。现在成本是344:

SELECT OL.PRODUCT_ID
FROM ORDER_LINES OL
WHERE EXISTS
  (SELECT ORDER_ID 
   FROM ORDERS
   WHERE CUSTOMER_ID = 474871
         AND ORDER_ID = OL.ORDER_ID)
OR EXISTS
  (SELECT ORDER_ID
   FROM ORDERS
   WHERE CUSTOMER_ID IN 
     (SELECT CUSTOMER_ID 
      FROM CUSTOMERS 
      WHERE UPPER(FIRST_NAME) = 'EDGAR')
  AND ORDER_ID = OL.ORDER_ID);

有什么突出的,我可能会试图降低成本吗? 以下是解释计划的屏幕截图:Explain Plan

ERD的屏幕截图:ERD

3 个答案:

答案 0 :(得分:2)

查看成本是误导性的,可能会导致您进行实际上并不有益的更改。引用Tom Kyte,“你无法将2个查询的成本相互比较.......它们也可能是随机数字。”

检查查询性能的最佳方法是实际查询查询,理想情况下使用实际数据。您还应该对过早优化保持警惕。你的第一个问题很简单;除非出现性能问题,否则我会坚持使用它。

答案 1 :(得分:1)

我很好奇引擎是否足够智能以在连接之前应用where子句...如果它在连接之后执行它,那么它必须扫描的结果比它们需要的大... ...如果将限制条件移动到连接,则会发生这种情况,因此必须在连接发生之前对其进行评估。 (完全可以预期这是599或更低。只是不知道它会不会更少......

SELECT OL.PRODUCT_ID
FROM CUSTOMERS C 
INNER JOIN ORDERS O       
  ON (C.CUSTOMER_ID = O.CUSTOMER_ID)
 AND (C.customer_ID = 47871 OR upper(C.First_name) = 'EDGAR')
INNER JOIN ORDER_LINES OL ON (O.ORDER_ID = OL.ORDER_ID)
INNER JOIN PRODUCTS P     ON (OL.PRODUCT_ID = P.PRODUCT_ID)
GROUP BY OL.Product_ID

我想知道OR是否导致问题....

如果你运行它没有或减少多少费用

然后如果将两个集合合并而不是使用或。

会发生什么
SELECT OL.PRODUCT_ID
FROM CUSTOMERS C 
INNER JOIN ORDERS O       
  ON (C.CUSTOMER_ID = O.CUSTOMER_ID)
INNER JOIN ORDER_LINES OL ON (O.ORDER_ID = OL.ORDER_ID)
INNER JOIN PRODUCTS P     ON (OL.PRODUCT_ID = P.PRODUCT_ID)
WHERE  C.customer_ID = 47871 
UNION
SELECT OL.PRODUCT_ID
FROM CUSTOMERS C 
INNER JOIN ORDERS O       
  ON (C.CUSTOMER_ID = O.CUSTOMER_ID)
INNER JOIN ORDER_LINES OL ON (O.ORDER_ID = OL.ORDER_ID)
INNER JOIN PRODUCTS P     ON (OL.PRODUCT_ID = P.PRODUCT_ID)
WHERE upper(C.First_name) = 'EDGAR')

答案 2 :(得分:1)

SELECT OL.PRODUCT_ID
FROM ORDER_LINES OL
WHERE OL.ORDER_ID IN 
        (SELECT ORDER_ID FROM ORDERS
         WHERE CUSTOMER_ID IN (SELECT CUSTOMER_ID FROM CUSTOMERS 
                               WHERE CUSTOMER_ID = 474871 OR UPPER(FIRST_NAME) = 'EDGAR')
        );

我想OL.ORDER_ID上有一个索引(现在你已经完全扫描了ORDER_LINES)