【问题标题】:Efficiency of joining subqueries in SQL Server在 SQL Server 中加入子查询的效率
【发布时间】:2013-02-26 17:12:44
【问题描述】:

我在 SQL Server 2008 R2 中有一个客户和订单表。两者都有关于客户 ID 的索引(称为id)。我需要返回 customers 表中所有客户的详细信息以及 orders 表中的信息,例如第一个订单的详细信息。

我目前在订单表的子查询中加入了我的客户表,该子查询返回了我需要的有关订单的信息。例如:

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 很陌生,想了解我是否有效地执行此操作。我最终在一个选择查询中将很多这样的子查询加入到客户表中,并且可能需要数十分钟才能运行。

那么我这样做效率高还是可以改进?例如,我不确定我在订单表中的 id 索引是否有任何用途,也许我可以通过首先创建子查询中内容的临时表并在 id 上创建唯一索引来加快查询速度临时表,所以 SQL Server 知道 id 现在是一个唯一列,然后将我的客户表加入这个临时表?我的客户和订单表中通常有一两百万行。

非常感谢!

【问题讨论】:

  • 从可读性的角度来看,大多数 SQL 开发人员会尽量避免这样的嵌套子查询。在需要像这样链接派生表的情况下,首选是通过 WITH 命令前缀来使用 CTE。就性能而言,它不应该有任何区别,这只是约定和可读性的问题。

标签: sql sql-server join subquery left-join


【解决方案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

在您的上述查询中,您需要小心放置括号的位置,因为我认为它不会起作用。此外,您在结果中返回产品,但不包括在嵌套子查询中。

【讨论】:

  • 如果订单表太大并且没有使用客户 ID 进行过滤,它必须在子查询中执行大量操作,因为它不相关。
【解决方案2】:

对于刚刚学习 SQL 的人来说,您的查询看起来不错。

客户索引可能会也可能不会用于查询——您需要查看执行计划。 orders(id, order_date) 上的索引可以非常有效地用于 row_number 函数。

一条评论是关于字段的命名。 orders.id 字段不应是客户 ID。这应该类似于“orders.Customer_Id”。保持跨表的命名系统一致将对您将来有所帮助。

【讨论】:

    【解决方案3】:

    试试这个...它很容易理解

    ;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
    

    【讨论】:

    • 如果订单表太大并且没有使用客户 ID 进行过滤,它必须在 CTE 内执行大量操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多