如何在不添加索引的情况下显着提高查询的性能?

时间:2013-01-09 21:27:49

标签: sql oracle

我有以下伪查询有人写道:

SELECT custId, orderId, col1, col2
FROM (SELECT c.id AS custId, o.id AS orderId,
      ROW_NUMBER() OVER(PARTITION BY c.id, o.id
                        ORDER BY d.col1, d.col2) AS RANK
      FROM customers c
      INNER JOIN orders o ON c.id = o.custId
      INNER JOIN orderDetails d ON o.id = d.orderId
      WHERE d.col3 IS NULL)
WHERE RANK = 1
  • c.id(custId)和o.id(orderId)是唯一的索引字段。
  • customers表有大约200万条记录
  • 订单表有~37万条记录
  • orderDetails表有~6.2亿条记录

不幸的是,这个查询花费了不明的时间(> 2小时),我的任务是解决这个问题。到目前为止,我已经提出了一个运行速度相当快的替代方案(但它仍然是完全不可接受的恕我直言):

SELECT custId, orderId, col1, col2
FROM (SELECT custId, orderId, col1, col2,
             ROW_NUMBER() OVER(PARTITION BY custId, orderId
                               ORDER BY col1, col2) AS RANK
      FROM (SELECT c.id AS custId, o.id AS orderId, d.col1, d.col2, d.col3
            FROM customers c
            INNER JOIN orders o ON c.id = o.custId
            INNER JOIN orderDetails d ON o.id = d.orderId)
      WHERE col3 IS NULL
WHERE RANK = 1

唉,我无法添加任何索引或查看基于这些表的查询的执行计划,所以我有点不知道如何重写/构造它以显着更快地运行= /。希望你们中的一位专家有一个更好的想法...我不是因为这个特定的查询而特别要求,而是因为我们有很多这样的查询需要像这样重写,我试图了解主要问题是什么这些是/我如何才能最好地解决它们。

1 个答案:

答案 0 :(得分:0)

如果没有看到原始查询的解释计划,我现在只能考虑以下查询(可能需要更正语法,但总体思路将保持不变): -

with d as 
(select orderid, col1, col2
from (select orderid, col1, col2,
row_number() over (partition by orderID order by col1,col2) as RANK
from orderDetails
where col3 is null)
where RANK=1)
select c.id as custID, o.id as orderID, d.col1, d.col2
from customers c inner join orders o on c.id=o.custID
inner join d on o.id=d.orderid;

您可能需要处理客户,订单和临时表'd'的连接顺序,以便获得正确的组合(以便首先连接具有较少记录数的表)。

在您的查询中,您正在加入表,然后您将获取每个c.id和o.id组合具有最小值col1和col2组的记录。根据您的查询,我认为通过c.id取出分区是安全的,因为col1和col2依赖于orderID而不依赖于customerID。因此,具有相同orderID的多个customerID将具有相同的col1和col2值。

因此,上面的查询首先获取每个orderID的col1和col2组的最小值,然后将它们与其余的表连接起来。