2009-04-22 6 views
1

Je veux créer une "vue" pour éliminer la même sous-requête de trois lignes d'environ 90 requêtes dans une application sur laquelle je travaille.L'utilisation d'une procédure stockée en tant que vue "dynamique"?

Le problème est le sous-requête contient une condition basée sur une variable.

SELECT * FROM items WHERE id NOT IN (
    SELECT item_id FROM excluded_items WHERE user_id = 123 
); 

Si ce n'était pas variable, je pourrais simplement faire une vue et en avoir fini avec elle.

Je ne suis pas sûr de ce qu'il faut faire dans ce cas cependant. En adoptant la même mentalité derrière une vue que je suis tenté de faire une procédure stockée qui renvoie le jeu d'enregistrement souhaité, afin qu'il puisse être appelé quelque chose comme ceci:

SELECT * FROM user_items(123); 

Maintenant, j'ai un seul endroit pour mettre à jour cet article l'exclusion et d'autres conditions, mais je ne suis pas sûr de savoir comment l'indexation est affectée si je veux joindre les résultats de ce SP contre d'autres tables?

Alors est-ce bon/mauvaise pratique? Y a-t-il une autre façon de le faire, ou devrais-je simplement l'aspirer et continuer à répliquer cette sous-requête?

Répondre

3

Comme d'habitude votre kilométrage peut varier. Si vous craignez que ce soit une bonne pratique en termes de syntaxe de votre code, je ne pense pas que cela soit important. Il est assez normal d'utiliser une procédure stockée pour renvoyer des jeux d'enregistrements et si cela vous permet d'économiser du temps de développement - alors pourquoi ne pas le faire? Cependant, si vous avez déterminé que le coût de votre requête s'exécute en temps et en heure de manière négative, votre entreprise coûte plus cher que votre productivité en tant que programmeur, mais ne va pas du tout avec les procédures stockées.

J'ai entendu beaucoup de plaisanteries au cours des années sur les procédures stockées de personnes en les appelant mal aux meilleures pratiques. La conclusion à laquelle je suis arrivé est comme toujours d'utiliser le bon outil pour le travail.

Pour déterminer la façon dont le changement affecte exactement la performance, exécuter quelques requêtes de test en utilisant:

EXPLAIN ANALYZE SELECT * FROM items WHERE id NOT IN (
    SELECT item_id FROM excluded_items WHERE user_id = 123 
); 

puis

EXPLAIN ANALYZE SELECT * FROM user_items(123); 

Ensuite, comparez les temps d'exécution et les plans de requête. Je pense que vous serez alors en mesure de prendre une décision plus éclairée.

+0

Merci Elie. J'ai effectivement analysé les requêtes tout en actualisant cette page :-) Jusqu'à présent les SP sont plus lents mais les différences sont négligeables. Je pense que je suis vraiment intéressé de savoir s'il y a des pièges à côté de la performance que je n'ai pas pris en compte. Jusqu'à présent, le consensus semble être de rouler avec les PS, merci pour votre réponse! –

1

Je pense que la solution de procédure stockée est plus DRY et améliore vraiment la lisibilité. Bien que je préfère certainement utiliser des vues lorsque cela est possible (en particulier avec les règles puissantes de PostgreSQL), je ne peux pas penser à une meilleure façon d'exprimer cela.

-2

ayant le même SQL dans 90 endroits peuvent être résolus du côté client aussi. Par exemple, créer une fonction qui construit la chaîne SQL:

public string SqlItemsForUser(int iUserId) { 
    return "SELECT * FROM items WHERE id NOT IN (" + 
     "SELECT item_id FROM excluded_items WHERE user_id = " + 
     Convert.ToString(iUserId) + ");"; 
} 

Vous pouvez appeler cette fonction en 90 endroits, donc si vous devez changer la sous-requête, il suffit de le changer en un seul endroit.

2

Avez-vous essayé quelque chose comme

create view user_items as (
    select i.*, u.id as user_id 
    from (items i cross join users u) 
     left join excluded_items e 
     on (i.id = e.item_id 
     and u.id = e.user_id) 
    where e.item_id is null 
); 

déjà? Je l'ai testé avec PostgreSQL 8.3, qui est capable de tirer la condition sur la user_id dans la jointure croisée si vous utilisez la vue dans les requêtes simples comme

select * 
    from user_items ui 
    where user_id = 1; 

Si vos requêtes en utilisant ce point de vue deviennent trop compliquées pour l'optimiseur de requête pour trouver la possibilité de Tirez la condition sur id_utilisateur dans la jointure croisée et la jointure complète est calculée, vous pouvez toujours jouer avec certains parameters de l'optimiseur de requête pour l'obtenir à nouveau.

Questions connexes