0

我有以下某人写的伪查询:

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) 是唯一的索引字段。
  • 客户表有大约 200 万条记录
  • 订单表有约 3700 万条记录
  • 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

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

4

1 回答 1

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 组的最小值,然后将它们与剩余的表连接起来。

于 2013-01-09T23:25:41.447 回答