2012-09-17 1 views
0

Mon cas d'utilisation est de récupérer des factures pour un client et un code de format pour chaque facture trouvée par une jointure à une table customer_list qui se joint à une table de codes généralisée pour élaborer le code de format. Une version simplifiée de ma requête suit, qui fonctionne correctement, mais la sous-requête retournerait environ 5k de lignes, je dois me demander comment cela pourrait être optimisé pour que la sous-requête ne contienne pas autant de lignes.Comment puis-je optimiser un select imbriqué?

select i.invoice_number, 
     f.format_code 
    from invoices i 
    left join (
    select gc.code_1 as format_code, 
      ls.account 
     from gen_codes gc, 
      customer_list ls 
    where gc.code_name = 'invoice-format' 
     and gc.code_1 <> '' 
     and ls.list_type = gc.code_value 
) f on account = i.account 
     or account = i.billing_account 
where i.account = :accountNumber 

NOTE: Pas toutes les factures ont un code de format, ce qui est bien et pourquoi je joue une jointure gauche.

MISE À JOUR: Une requête similaire sans l'aide d'une sélection interne serait de la forme suivante:

select i.invoice_number, 
     f.code_1 as format_code 
    from invoices i 
    left join customer_list ls on 
    (account = i.account or account = i.billing_account) and ls.list_type in (
      select code_value 
      from gen_codes 
      where code_name = 'invoice-format' 
       and code_1 <> '' 
     ) 
    left join gen_codes f on code_value = ls.list_type 
         and code_name = 'invoice-format' 
         and code_1 <> '' 

Je sens cette dernière version peut être plus efficace car il n'y a que deux enregistrements douzaine de gen_codes avec la requête correspondante tandis que customer_list contient ~ un demi-million d'enregistrements avec ~ 5k correspondant dans la première version.

+0

Pour m'aider à mieux comprendre les instructions select internes, comment les moteurs SQL interprètent-ils cela? Est-ce qu'ils exécutent le select interne avant l'instruction select externe? Et si oui, ce résultat est réutilisé pour le reste de la sélection, de sorte qu'il n'a été exécuté qu'une seule fois? –

Répondre

0

je l'écrire comme suit:

obtenir toutes les factures correspondant à un compte ou de facturation (en utilisant JOIN et sur les clauses) et obtenir que les gen_codes associés aux list_types du compte adapté (en utilisant LEFT JOIN) dont le nom de code est 'facture-format' et gc.code_1 n'est pas vide.

SELECT 
    i.invoice_number, 
    gc.code_1 as format_code 
FROM 
    invoices i 
    JOIN customer_list ls 
    ON 
     (i.billing_account = ls.account OR i.account = ls.account) AND 
     i.account = :accountNumber 
    LEFT JOIN gen_codes gc 
    ON 
     ls.list_type = gc.code_value AND 
     gc.code_name = 'invoice-format' AND 
     gc.code_1 != '' 

Cela élaguer les enregistrements customer_list qui ne correspond pas à l'entrée accountNumber dès le départ, par rapport à la sous-requête dans votre question.

+0

Un client n'a peut-être pas d'entrée 'gen_codes' pour le type de liste que je veux 'NULL' renvoyé comme' format_code' qui fonctionne correctement dans ma requête. La jointure à gen_codes les ferait donc tomber. –

+0

Notez également que faire la jointure à 'gen_codes' une 'jointure à gauche' ne fonctionnera pas non plus car un client peut apparaître sur plusieurs listes qui peuvent ne pas être liées à la liste des formats de facture. –

+0

pourriez-vous s'il vous plaît jeter un oeil à la requête modifiée (j'ai essayé de décrire ce que j'ai l'intention de faire avec la requête, ci-dessus), quand vous avez une chance? L'idée de base est d'élaguer les enregistrements customer_list en utilisant le filtre de numéro de compte. – Vikdor