2009-07-28 10 views
1

Le problème: nous avons une requête de recherche très complexe. Si son résultat donne trop peu de lignes, nous étendons le résultat en UNIONing la requête avec une version moins stricte de la même requête.Performance SQL: UNION ou ORDER BY

Nous discutons si une approche différente serait plus rapide et/ou meilleure en qualité. Au lieu de UNIONing nous créerions une fonction sql personnalisée qui retournerait un score correspondant. Ensuite, nous pourrions simplement commander par ce score correspondant.

En ce qui concerne les performances: sera-t-il plus lent qu'un UNION?

Nous utilisons PostgreSQL.

Toutes les suggestions seraient grandement appréciées.

Merci beaucoup Max

Répondre

2

Vous voulez commander par la "valeur de retour" de votre fonction personnalisée? Ensuite, le serveur de base de données ne peut pas utiliser un index pour cela. Le score doit être calculé pour chaque enregistrement de la table (qui n'a pas été exclu avec une clause WHERE) et stocké dans un stockage temporaire/table. Ensuite, la commande par est effectuée sur cette table temporaire. Donc, cela peut facilement devenir plus lent que vos requêtes syndicales (en fonction de vos déclarations syndicales bien sûr).

+1

Oui, il suffit de créer un index d'expression sur la sortie de la fonction –

+1

Oui, il serait possible que ce soit le même appel de fonction à chaque fois, comme dans l'exemple du manuel "WHERE lower (col1) = 'value' "Mais Max veut calculer une sorte de score correspondant à une chaîne de recherche en constante évolution." Indexes on Expressions ": http://www.postgresql.org/docs/8.4/interactive/indexes-expressional.html – VolkerK

6

Une réponse définitive ne peut être donnée si l'on mesure les performances des deux approches dans des environnements réalistes. Tout le reste est de deviner au mieux.

Il y a tellement de variables en jeu ici - la structure des tables et les types de données qu'elles contiennent, la distribution des données, le type d'index dont vous disposez, le poids de la charge sur le serveur - Il est presque impossible de prédire un résultat, vraiment. Donc vraiment - mon meilleur conseil est: essayez les deux approches, sur le système live, avec des données en direct, pas seulement avec quelques douzaines de lignes de test - et mesurez, mesurez, mesurez.

Marc

+0

+1 - conseil sonore – AdaTheDev

+0

peut sembler un peu frustrant, mais le plus souvent, c'est vraiment presque le seul conseil disponible ...... –

+0

+1 - ne pas oublier d'utiliser les plans et les index – northpole

1

Pour ajouter mon petit peu ...

+1 à marc_s, tout à fait d'accord avec ce qu'il a dit - je dirais seulement, vous avez besoin d'un serveur db de test avec des volumes de données réalistes pour tester sur, par opposition au serveur de production. Pour l'approche de la fonction, la fonction serait exécutée pour chaque enregistrement, puis triée par ce résultat - il ne s'agirait pas d'une colonne indexée et je m'attendrais donc à voir un impact négatif sur les performances. Cependant, l'ampleur de cet impact et son caractère négatif par rapport au temps cumulé de l'autre approche ne seront connues que des tests.

1

En PostgreSQL 8.3 et au-dessous, UNION implicite DISTINCT qui impliquait le tri, cela signifie ORDER BY, UNION et DISTINCT étaient toujours même efficacité, puisque le Atter deux aways ont utilisé le tri.

Sur PostgreSQL 8.3, cette requête renvoie les résultats triés:

SELECT * 
FROM generate_series(1, 10) s 
UNION 
SELECT * 
FROM generate_series(5, 15) s 

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 

Depuis PostgreSQL 8.4 il est devenu possible d'utiliser HashAggregate pour UNION qui peut être plus rapide (et presque est toujours), mais ne garantit pas la sortie ordonnée.

La même requête renvoie les éléments suivants sur PostgreSQL 8.4:

SELECT * 
FROM generate_series(1, 10) s 
UNION 
SELECT * 
FROM generate_series(5, 15) s 

10 
15 
8 
6 
7 
11 
12 
2 
13 
5 
4 
1 
3 
14 
9 

, et comme vous pouvez voir les resuts ne sont pas triées.

PostgreSQL change list mentionne ceci:

SELECT DISTINCT et UNION/INTERSECT/EXCEPT ne produisent toujours triés (Tom)

Ainsi, dans de nouvelles PostgreSQL versions, je conseille d'utiliser UNION, car il est plus flexible .

Dans les anciennes versions, les performances sont les mêmes.