Django order_by 导致 LEFT JOIN

Posted

技术标签:

【中文标题】Django order_by 导致 LEFT JOIN【英文标题】:Django order_by causes LEFT JOIN 【发布时间】:2011-08-22 01:27:16 【问题描述】:

谁能告诉我为什么当我添加order_by() 时,获取输出的查询会从INNER JOIN 更改为LEFT OUTER JOIN

有什么办法可以保留INNER JOIN-ness?

data = models.RetailSalesFact.objects.values('customer_key__customer_state', 
                                             'date_key__calendar_month_name')
data = data.filter(date_key__calendar_year=year)
data = data.annotate(sales=Sum('sales_quantity'))
data = data.order_by('date_key__calendar_month_name')

之前:

SELECT Customer_Dimension.Customer_State, Date_Dimension.Calendar_Month_Name,
       SUM(Retail_Sales_Fact.Sales_Quantity) AS sales 
    FROM Retail_Sales_Fact  
    INNER JOIN Customer_Dimension 
        ON (Retail_Sales_Fact.Customer_Key = Customer_Dimension.Customer_Key) 
    INNER JOIN Date_Dimension 
        ON (Retail_Sales_Fact.Date_Key = Date_Dimension.Date_Key) 
    WHERE Date_Dimension.Calendar_Year = ?  
    GROUP BY Customer_Dimension.Customer_State, 
             Date_Dimension.Calendar_Month_Name 
    ORDER BY Date_Dimension.Calendar_Month_Name ASC

之后:

SELECT Customer_Dimension.Customer_State, Date_Dimension.Calendar_Month_Name, 
       SUM(Retail_Sales_Fact.Sales_Quantity) AS sales 
    FROM Retail_Sales_Fact 
    INNER JOIN Customer_Dimension 
        ON (Retail_Sales_Fact.Customer_Key = Customer_Dimension.Customer_Key) 
    LEFT OUTER JOIN Date_Dimension 
        ON (Retail_Sales_Fact.Date_Key = Date_Dimension.Date_Key) 
    WHERE Date_Dimension.Calendar_Year = ?  
    GROUP BY Customer_Dimension.Customer_State, 
             Date_Dimension.Calendar_Month_Name 
    ORDER BY Date_Dimension.Calendar_Month_Name ASC

【问题讨论】:

【参考方案1】:

我猜 ORM 正在执行 LEFT JOIN,因为它无法判断 INNER JOIN 的 where 限制是否比排序子句更具限制性。因为它认为它需要对每条记录进行排序,无论它是否匹配。

您可以使用Raw SQL 强制INNER JOIN。或者您可以通过在filter 之前应用order_by 来欺骗ORM?

【讨论】:

【参考方案2】:

您在外部表上放置了一个过滤器 (date_dimension__calendar_year=year),因此无论您使用内连接还是左外连接,结果集之间都没有区别。

order-by 是在中间结果集上处理的——如果在内部连接的表上完成,那么它必须在组合表之后完成——这意味着读取一个:组合记录;阅读二:排序合并记录。

但是,如果仅在外连接表上完成排序,在这种情况下,这就是您所要求的,那么您的查询优化器可能能够避免读取整个集合两次,而是,只读取了外部表两次。您的优化器可能会认为这是在处理能力方面的节省。

这只是一个猜测。无论哪种方式,您的结果集都应该是相同的。我想知道你是否可以两种方式都计时,看看哪一种需要更长的时间。

【讨论】:

结果集是相同的,但是 INNER JOIN 和 LEFT JOIN 之间的时间相当重要。它可能不会对相对较小的数据集造成任何损害,但随着表格填满,它会产生很大的影响。 所以inner-join + order-by比left-outer-join + order-by花费的时间更少?我以为您最初是在比较内部连接(没有排序依据)。 尝试重新排序您的 Group-by 声明。您的数据集实际上被排序了两次——首先按 Group-by,然后按 order-by。把group-by改成这个:GROUP BY Date_Dimension.Calendar_Month_Name,Customer_Dimension.Customer_State,然后去掉order-by子句,能不能得到你想要的结果?

以上是关于Django order_by 导致 LEFT JOIN的主要内容,如果未能解决你的问题,请参考以下文章

Django:Order_by 多个字段

DJANGO:如何使用包含 order_by 的模型创建管理视图?

080:Django数据库QuerySet API详解-order_by:

Django QuerySet 过滤器 + order_by + 限制

Django order_by() 没有正确排序

Django1.4:如何在模板中使用order_by?