2011-05-09 2 views
7

Quelqu'un peut-il me dire pourquoi quand j'ajoute le order_by() la requête qui obtient des changements de sortie d'un INNER JOIN à LEFT OUTER JOIN?Django order_by causes LEFT JOIN

Y at-il un moyen de préserver le 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') 

Avant:

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 

Après:

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 
+0

Réponse mise à jour ... – FallenAngel

Répondre

1

Je suppose l'ORM fait un LEFT JOIN parce qu'il ne peut pas dire si les INNER JOIN « s où la restriction est plus ou moins restrictive que la clause de commande. Comme il pense qu'il a besoin de commander chaque enregistrement, indépendamment du fait qu'il correspond ou non. Vous pouvez forcer un INNER JOIN en utilisant Raw SQL. Ou peut-être vous pouvez tromper l'ORM en appliquant le order_by avant le filter?

1

Vous placez un filtre sur la table externe (date_dimension__calendar_year = année), il n'y aura donc pas de différence entre le jeu de résultats, que vous utilisiez une jointure interne ou une jointure externe gauche. L'ordre d'exécution est traité sur un ensemble de résultats intermédiaire - s'il est effectué sur les tables jointes à l'intérieur, alors il doit être fait après que les tables sont combinées - ce qui signifie lire un: combiner les enregistrements; lisez deux: commandez les enregistrements combinés. Mais si l'ordre est fait uniquement sur la table externe, ce qui dans ce cas est tout ce que vous demandez, alors votre optimiseur de requête peut être capable d'éviter de lire deux fois le jeu entier, et Au lieu de cela, ne lisez que deux fois la table externe. Votre optimiseur peut reconnaître cela comme une économie en termes de puissance de traitement.

C'est juste une supposition. Votre jeu de résultats devrait être identique dans les deux cas. Je me demande si vous pouvez le faire dans les deux sens, et voir lequel prend plus de temps.

+1

le jeu de résultats est le même, mais le temps entre un INNER JOIN et un LEFT JOIN est assez important. Cela ne nuira probablement à rien sur des jeux de données relativement petits, mais cela a un impact important à mesure que les tableaux se remplissent. –

+0

Donc la jointure interne + l'ordre-par prend moins de temps que gauche-externe-joint + ordre-par? Je pensais que vous étiez à l'origine en train de comparer la jointure interne (sans ordre). – Chains

+0

Essayez de réorganiser votre relevé Group-by. Votre ensemble de données est actuellement trié deux fois - d'abord par Group-by, puis par order-by. Pouvez-vous obtenir le résultat que vous voulez en changeant group-by à ceci: GROUP BY Date_Dimension.Calendar_Month_Name, Customer_Dimension.Customer_State, et puis se débarrasser de la clause order-by? – Chains