Django的order_by导致LEFT JOIN

7

有人能告诉我为什么当我添加order_by()后,输出的查询会从INNER JOIN变成LEFT OUTER JOIN吗?

是否有任何方法可以保留INNER JOIN?

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')

Before:

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
2个回答

2

您正在对外部表(date_dimension__calendar_year=year)进行过滤,因此无论您使用内连接还是左外连接,结果集都不会有区别。

order-by在中间结果集上处理--如果在内连接的表上执行,则必须在合并表之后执行--这意味着读取一次:组合记录;读取两次:对组合记录进行排序。

但是,如果仅对外部连接的表执行order-by,这正是您所要求的,那么您的查询优化器可能能够避免两次读取整个集合,而只读取外部表两次。您的优化器可能会认为这是节省处理能力的一种方法。

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


1
结果集是相同的,但内连接和左连接之间的时间差异相当大。在相对较小的数据集上可能不会有影响,但随着表填充,它会产生很大影响。 - Al W
内连接 + 排序比左外连接 + 排序所需的时间少?我原本以为你是在比较没有排序的内连接。 - Chains
尝试重新排序您的Group-by语句。实际上,您的数据集被排序了两次--首先按Group-by排序,然后按order-by排序。通过将group-by更改为以下内容:GROUP BY Date_Dimension.Calendar_Month_Name,Customer_Dimension.Customer_State,然后去掉order-by子句,您能否获得所需结果? - Chains

1

我猜ORM执行了一个LEFT JOIN ,因为它无法确定INNER JOIN的where限制是否比排序子句更严格还是更宽松。因为它认为需要对每个记录进行排序,而不管它是否匹配。

你可以通过使用原始SQL来强制进行INNER JOIN。或者也许你可以在filter之前应用order_by来愚弄ORM?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接