web-dev-qa-db-ja.com

SQLServerでサブクエリに参加する効率

SQL Server 2008R2に顧客と注文のテーブルがあります。どちらも顧客IDにインデックスがあります(idと呼ばれます)。顧客テーブル内のすべての顧客に関する詳細と、最初の注文の詳細など、注文テーブルからの情報を返す必要があります。

私は現在、ordersテーブルのサブクエリでcustomersテーブルに結合したままにしており、サブクエリは注文について必要な情報を返します。例えば:

SELECT c.id
        ,c.country      
        ,First_orders.product
        ,First_orders.order_id
FROM customers c

LEFT JOIN   SELECT( id, 
                    product 
            FROM (SELECT    id
                            ,product
                            ,order_id
                            ,ROW_NUMBER() OVER (PARTITION BY id ORDER BY Order_Date asc) as order_No 
                        FROM orders) orders
            WHERE Order_no = 1) First_Orders
ON c.id = First_orders.id

私はSQLにまったく慣れていないので、これを効率的に行っているかどうかを理解したいと思います。このようなかなりの数のサブクエリを1つの選択クエリでcustomersテーブルに結合することになり、実行に数十分かかる場合があります。

それで、私はこれを効率的に行っていますか、それとも改善できますか?たとえば、ordersテーブルのidのインデックスが役立つかどうかはわかりません。最初にサブクエリにあるものの一時テーブルを作成し、idの一意のインデックスを作成することでクエリを高速化できます。 SQLServerがidが一意の列であることを認識し、顧客テーブルをこの一時テーブルに結合するための一時テーブル?私は通常、顧客テーブルと注文テーブルに100万行または200万行あります。

よろしくお願いします!

6
user2112153

サブクエリの1つを削除して、もう少し効率的にすることができます。

SELECT c.id
        ,c.country      
        ,First_orders.product
        ,First_orders.order_id
FROM customers c
   LEFT JOIN  (SELECT id
                    ,product
                    ,order_id
                    ,ROW_NUMBER() OVER (PARTITION BY id ORDER BY Order_Date asc) as order_No 
               FROM orders) First_Orders
     ON c.id = First_orders.id AND First_Orders.order_No = 1

上記のクエリでは、かっこを配置する場所に注意する必要があります。これは機能しないと思います。また、結果には製品が返されますが、ネストされたサブクエリには含まれません。

6
sgeddes

SQLを学んでいるだけの人にとって、クエリはかなり見栄えがします。

顧客のインデックスはクエリに使用される場合と使用されない場合があります。実行プランを確認する必要があります。 orders(id, order_date)のインデックスは、row_number関数に非常に効果的に使用できます。

1つのコメントはフィールドの命名についてです。フィールドorders.idは顧客IDであってはなりません。 'orders.Customer_Id`のようになります。ネーミングシステムをテーブル間で一貫性を保つことは、将来的に役立ちます。

2
Gordon Linoff

これを試してください...理解しやすいです

;WITH cte
AS (
    SELECT id
        ,product
        ,order_id
        ,ROW_NUMBER() OVER (
            PARTITION BY id ORDER BY Order_Date ASC
            ) AS order_No
    FROM orders
    )
SELECT c.id
    ,c.country
    ,c1.Product
    ,c1.order_id
FROM customers c
INNER JOIN cte c1 ON c.id = c1.id
WHERE c1.order_No = 1
1
Utsav Anand