2017-03-24 2 views
2

je la sous-requête suivante:Améliorer les performances des sous-requête corrélée avec des jointures internes

SELECT 
    b.state, 
    b.city, 
    count(b.state) as totalCount, 
    sum(cast(replace(b.annual_prod, ',','.') as decimal)) AS annualProd, 
    (
    SELECT count(size_k) 
    FROM opentable_clean a 
    WHERE a.state = b.state 
     AND a.city = b.city 
     AND cast(replace(a.size_k, ',','.') as decimal) >= 20 
    GROUP BY a.state, a.city 
) as Above20k 
FROM opentable_clean b 
GROUP BY b.state, b.city 
ORDER by annualProd DESC; 

Cela fonctionne, mais la requête est très inefficace et prend beaucoup de temps compte tenu de la taille de la table sous-jacente. Je pense qu'en utilisant une jointure interne pourrait améliorer la performance mais je n'ai pas pu essayer celui qui fonctionne.

Toutes les suggestions seraient utiles car je suis nouveau à sql.

+3

Il semble que vous stockez des valeurs numériques sous forme de chaînes ('a.size_k' en particulier), et que la manipulation de conversion de type & chaîne dans votre clause interne "where" est probablement pas SARG-capable. Pouvez-vous corriger la table pour stocker vos données numériques correctement? – alroc

+1

Quels SGBD utilisez-vous? Postgres? Oracle? –

+0

J'utilise postgres – user3003374

Répondre

1

Ce n'est pas vous joindre à vous cherchez, mais une condition sur la fonction d'agrégation .. quelque chose comme ça

select b.state, 
    b.city, 
    count(b.state) as totalCount, 
    sum(cast(replace(b.annual_prod, ',','.') as decimal)) AS annualProd, 
    SUM(CASE 
      WHEN cast(replace(a.size_k, ',','.') as decimal) >= 20 
      THEN 1 
      ELSE 0 END) as Above20k 
    FROM opentable_clean b 
    GROUP BY b.state, b.city 
    ORDER by annualProd DESC; 

Vous verrez encore quelques succès à faire tous les remplace - si vous pouvez créer même juste une colonne persistante calculée sur la table pour stocker les chaînes correctement, votre requête serait plus performante.

La raison pour laquelle cela vous aidera: au lieu d'exiger que le moteur scanne la table deux fois, il devrait être capable de faire tout cela en une seule fois, puisque vous ne travaillez qu'avec une seule table. Si vous utilisiez en fait une seconde table, vous voudriez utiliser le même type de méthode avec un JOIN approprié.

+0

Merci Dan. Cela a bien fonctionné. Je devais juste remplacer count avec somme dans votre solution ci-dessus. – user3003374

+0

Pas de problème. Si cette réponse vous a aidé, considérez la marquer comme acceptée - et pour référence future, il est toujours préférable d'étiqueter le SGBDR que vous utilisez dans la question originale (j'ai mis à jour le tag pour vous) –

+0

Je suis sûr que cela serait fonctionne comme pour 'SQL Server', mais' SUM' a aussi un sens. –

0

Si vous souhaitez améliorer les performances d'une requête, vous devez d'abord consulter le plan d'exécution et les statistiques io.

Pour voir un plan d'exécution, cliquez sur le bouton du plan d'exécution d'affichage.

Pour afficher les statistiques io, exécutez la requête après avoir exécuté SET STATISTICS IO ON. Les statistiques apparaîtront avec les messages.

S'il n'y a pas d'index, cette requête lit open_table b par tableScan/clusteredIndexScan, puis il va regrouper et lire open_table par tableScan/clusteredIndexScan pour chaque groupe.

L'indice le plus simple qui pourrait aider serait un indice (état, ville)

+0

Etes-vous sûr que OP utilise SQL Server? –