2010-03-16 3 views
0

J'ai été inspiré par les bonnes réponses de mon précédent question sur SQL. Maintenant, ce SQL est exécuté sur une base de données avec Interbase 2009. Il est d'environ 21 Go.Optimiser SQL avec Interbase

SELECT DistanceAsMeters, AddrDistance.Bold_Id, AddrDistance.Created, AddressFrom.CityName_CO as FromCity, AddressTo.CityName_CO as ToCity 
FROM AddrDistance 
LEFT JOIN Address AddressFrom ON AddrDistance.FromAddress = AddressFrom.Bold_Id 
LEFT JOIN Address AddressTo ON AddrDistance.ToAddress = AddressTo.Bold_Id 
Where DistanceAsMeters = 0 and PseudoDistanceAsCostKm = 0 
     and not AddrDistance.bold_id in (select bold_id from DistanceQueryTask) 
Order By Created Desc 

Il y a 840000 lignes avec AddrDistance 190000 lignes avec adresse et 4 avec DistanceQueryTask. La question est: est-ce que cela peut être fait plus rapidement? Je suppose, la même requête est exécutée plusieurs fois sélectionnez bold_id de DistanceQueryTask. Notez que je ne suis pas intéressé par les procédures stockées, tout simplement SQL :)

EDIT1 Voici le plan d'exécution actuel:

Statement: SELECT DistanceAsMeters, AddrDistance.Bold_Id, AddrDistance.Created, AddressFrom.CityName_CO as FromCity, AddressTo.CityName_CO as ToCity 
FROM AddrDistance 
LEFT JOIN Address AddressFrom ON AddrDistance.FromAddress = AddressFrom.Bold_Id 
LEFT JOIN Address AddressTo ON AddrDistance.ToAddress = AddressTo.Bold_Id 
Where DistanceAsMeters = 0 and PseudoDistanceAsCostKm = 0 
     and not AddrDistance.bold_id in (select bold_id from DistanceQueryTask) 
Order By Created Desc 

PLAN (DISTANCEQUERYTASK INDEX (RDB$PRIMARY218)) 
PLAN SORT (JOIN (JOIN (ADDRDISTANCE NATURAL,ADDRESSFROM INDEX (RDB$PRIMARY234)),ADDRESSTO INDEX (RDB$PRIMARY234))) 

Et oui, DistanceQueryTask est censé avoir un faible nombre si les lignes dans la base de données. L'utilisation de Left Join et les sous-requêtes ralentiront n'importe quelle requête.

+0

Avez-vous vérifié le plan d'exécution de la requête (ceci peut être fait avec les composants IBX, IBExpert et peut-être même avec IBConsole)? Il montre s'il y a des jointures naturelles au lieu d'indexées. – mjn

+0

Est-ce que DistanceQueryTask va toujours contenir un petit nombre d'enregistrements? – skamradt

Répondre

2

Vous pouvez obtenir des améliorations avec les bons index (sur Bold_id, Distancemètres, PseudoDistanceAsCostKm) rappelez-vous que plus les indices augmentent la taille de la base de données

+1

La plus grande amélioration vient en indexant ces champs, merci. –

2

Je suppose que bold_id est votre clé, et donc correctement indexé.
Le remplacement de la sous-sélection et du non ... par une jointure peut aider l'optimiseur.

SELECT DistanceAsMeters, Bold_Id, Created, AddressFrom.CityName_CO as FromCity, AddressTo.CityName_CO as ToCity 
FROM AddrDistance 
LEFT JOIN Address AddressFrom ON AddrDistance.FromAddress = AddressFrom.Bold_Id 
LEFT JOIN Address AddressTo ON AddrDistance.ToAddress = AddressTo.Bold_Id 
LEFT JOIN DistanceQueryTask ON AddrDistance.bold_id = DistanceQueryTask.bold_id 
Where DistanceAsMeters = 0 and PseudoDistanceAsCostKm = 0 
    and DistanceQueryTask.bold_id is null 
Order By Created Desc 
+0

Cette requête donne 0 lignes, probablement parce que DistanceQueryTask.bold_id n'est jamais nulle car c'est la clé pour identifier les lignes. En dehors de cela, bold_id de AddrDistance et DistanceQueryTask ne peuvent jamais être identiques. –

+0

@Roland: Une jointure gauche combinée à un 'where right_table.Key is null' ne donne que les enregistrements de la table de gauche qui ne correspondent pas dans la table de droite (ceux où vous auriez les colonnes right_table null sans la clause where) –

2

Créer un index pour cette partie: (DistanceAsMeters = 0 et PseudoDistanceAsCostKm = 0) car il fait un (mauvais) scan de table pour elle: ADDRDISTANCE NATUREL

Et essayez d'utiliser la jointure au lieu de sous-sélection comme indiqué par François.

2

Comme le suggèrent Daniel et André, un index aide beaucoup.
Je suggérerais cet index (DistanceMeters, PseudoDistanceAsCostKm, Bold_id), parce que les 2 premières parties de l'index sont constantes, alors c'est une petite partie de l'index qui est nécessaire pour lire.

S'il est un fait que FromAddress et/ou ToAddress existent, vous pouvez modifier LEFT JOIN à INNER JOIN, car il est souvent plus rapide (l'optimiseur de requête peut faire quelques suppositions).