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) のみがインデックス付きフィールドです。
  • customers テーブルには最大 200 万件のレコードがあります
  • orders テーブルには最大 3,700 万件のレコードがあります
  • orderDetail テーブルには最大 6 億 2000 万のレコードがあります

残念ながら、このクエリには不明な時間 (> 2 時間) がかかり、私はこの問題を解決する任務を負っています。これまでのところ、かなり高速に実行される代替案を思いつきました(ただし、それでも完全に受け入れられないIMHOです):

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 グループの最小値を持つレコードを取得しています。あなたのクエリを見ると、col1 と col2 は customerID ではなく orderID に依存しているため、c.id によるパーティショニングを実行しても安全だと思います。したがって、同じ orderID を持つ複数の customerID は、col1 と col2 の値が同じになります。

したがって、上記のクエリは、最初に orderID ごとに col1 および col2 グループの最小値をフェッチし、次にそれらを残りのテーブルと結合します。

于 2013-01-09T23:25:41.447 に答える