我试图在不创建任何索引的情况下尽可能地降低此查询的成本。
这是原始查询,费用为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);
有什么突出的,我可能会试图降低成本吗? 以下是解释计划的屏幕截图:
ERD的屏幕截图:
答案 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)