2010-06-08 6 views
3

J'ai une table, Foo. Je lance une requête sur Foo pour obtenir les identifiants d'un sous-ensemble de Foo. Je veux ensuite exécuter un ensemble de requêtes plus compliqué, mais uniquement sur ces ID. Y a-t-il un moyen efficace de le faire? Le mieux que je puisse penser est de créer une requête telle que:sql choisir parmi un grand nombre d'ID

SELECT ... --complicated stuff 
WHERE ... --more stuff 
    AND id IN (1, 2, 3, 9, 413, 4324, ..., 939393) 

C'est-à-dire, je construis une énorme clause "IN". Est-ce efficace? Existe-t-il un moyen plus efficace de le faire, ou est le seul moyen de JOIN à la requête inital qui obtient les ID? Si cela aide, j'utilise SQLObject pour me connecter à une base de données PostgreSQL, et j'ai accès au curseur qui a exécuté la requête pour obtenir tous les ID. MISE À JOUR: Je dois mentionner que les requêtes les plus complexes reposent toutes sur ces ID ou créent plus d'ID à rechercher dans les autres requêtes. Si je devais faire une grande requête, je finirais par rejoindre six tables à la fois, ce qui pourrait être trop lent.

Répondre

6

Une technique que j'ai utilisée dans le passé consiste à placer les ID dans une table temporaire, puis à l'utiliser pour générer une séquence de requêtes. Quelque chose comme:

BEGIN; 
CREATE TEMP TABLE search_result ON COMMIT DROP AS 
    SELECT entity_id 
    FROM entity /* long complicated search joins and conditions ... */; 
-- Fetch primary entities 
SELECT entity_id, entity.x /*, ... */ 
FROM entity JOIN search_result USING (entity_id); 
-- Fetch some related entities 
SELECT entity_id, related_entity_id, related_entity.x /*, ... */ 
FROM related_entity JOIN search_result USING (entity_id); 
-- And more, as required 
END; 

Ceci est particulièrement utile lorsque les entités de résultats de recherche ont plusieurs one-to-many relations que vous souhaitez chercher sans soit a) faire N * M + 1 sélectionne ou b) faire une jointure cartésienne d'entités apparentées.

+0

Y a-t-il une différence entre faire cela et créer une vue temporaire? – Claudiu

+0

continuera à exécuter la requête, mais une table temporaire stocke simplement les résultats? ressemble à ce que je veux est ce dernier – Claudiu

+2

En créant une table temporaire, les résultats réels eux-mêmes sont spoulés, de sorte que la recherche potentiellement compliquée n'est exécutée qu'une seule fois. Avec une vue temporaire, les conditions de recherche seraient transférées dans chaque déclaration suivante. Si vos conditions de recherche sont simples, une vue peut être plus efficace. Si elles sont très complexes, la matérialisation des résultats dans une table temporaire sera gagnante. Je commencerais naturellement par utiliser une table temporaire, et peut-être que l'application conduisant cette utilisation une vue temporaire si elle détermine que les conditions de recherche sont assez simples par une règle empirique. – araqnid

0

Je pense que la jointure avec les critères pour sélectionner les ID sera plus efficace parce que l'optimiseur de requête a plus d'options pour faire la bonne chose. Utilisez le plan d'explication pour voir comment postgresql l'approche.

+0

mauvais essayer le plan expliquer. J'ai mis à jour pour mentionner que je finirais par rejoindre 6 tables ou plus, ce qui semble être trop long. – Claudiu

+0

Vous ne savez jamais, il est presque impossible de prédire. L'optimiseur est intelligent et utilise les statistiques de vos tables. Assurez-vous que votre base de données est analysée sous vide. En regardant le plan d'explication donne souvent des aperçus comme des index manquants, ou des index qui sont là et ne sont pas utilisés. –

1

Je pense qu'il pourrait être utile d'utiliser une vue. Créez simplement une vue avec votre requête d'ID, puis rejoignez cette vue via ID. Cela limitera vos résultats au sous-ensemble d'ID requis sans une instruction IN coûteuse. Je sais que l'instruction IN est plus coûteuse qu'une instruction EXISTS.

+0

ah ça ressemble à ce dont j'ai besoin. temps de google comment créer une vue. – Claudiu

0

Vous êtes certainement mieux avec un JOIN, cependant, une autre option est d'utiliser un sous select, à savoir

SELECT ... --complicated stuff 
WHERE ... --more stuff 
    AND id IN (select distinct id from Foo where ...) 
Questions connexes