2011-09-28 4 views
2

Je dois obtenir des informations à partir de deux bases de données. L'un est un ORACLE et l'autre est un DB2. Dans mon programme (C#) j'obtiens dans la première étape les informations de base de mes objets de la base de données ORACLE. Dans la deuxième étape, je veux ajouter les informations qui sont enregistrées dans le DB2. La table dans DB2 a une clé primaire composite et je ne suis pas sûr de savoir quelle est la meilleure façon de demander ou s'il y a une alternative que je ne vois pas pour le moment.Demande SQL avec clé primaire composite

Par exemple: COLUMN1 et COLUMN2 sont la clé primaire composite.

Variante 1:

SELECT * 
    FROM (SELECT COLUMN1, COLUNN2, COLUMN3, ..., COLUMN1||'_'||COLUMN2 AS ID 
      FROM TABLE1) AS TEMP 
    WHERE ID='2011_123456' 
    OR ID='2011_987654' 

Ici, je pense que l'inconvénient est que pour chaque ligne de la table la concaténation de chaîne est construit ainsi que la vitesse d'exécution est relativement lente parce que les colonnes de clé primaire sont indexées et le nouveau on n'est pas.

Variante 2:

SELECT COLUMN1, COLUMN2, COLUMN3, ..., COLUMN1||'_'||COLUMN2 AS ID 
    FROM TABLE1 
WHERE (COLUMN1='2011' AND COLUMN2='123456') 
    OR (COLUMN1='2011' AND COLUMN2='987654') 

Celui-ci est vraiment rapide, mais quand je reçois un SQL0954C d'exception (Pas assez de stockage est disponible dans le tas d'application pour traiter l'instruction).

Variante 3:

SELECT COLUMN1, COLUMN2, COLUMN3, ..., COLUMN1||'_'||COLUMN2 AS ID 
    FROM TABLE1 
WHERE COLUMN1 IN ('2011') 
    AND COLUMN2 IN ('123456','987654') 

Celui-ci est aussi lent par rapport à la variante 2.

Quelques chiffres plus Table1 a au moment environ. 600k lignes

J'ai essayé les variantes et a obtenu les temps d'exécution suivantes:
Pour 100 objets demandés:
Variante 1: 3900ms
Variante 2: 218ms

Pour 400 objets demandés:
Variante 1: 10983ms
Variante 2: 266ms

Pour 500 objets demandé:
Variante 1: 12796ms
V ariant 2: exception SQL0954C
Variante 3: 7061ms

Seulement en regardant les temps je préférerais la variante 2 mais il y a le problème avec l'exception.

Les bases de données ne sont pas sous mon contrôle et je n'ai que des droits SELECT. Que pensez-vous être le meilleur pour ce cas d'utilisation? Y a-t-il d'autres possibilités que je ne vois pas?

Cordialement,
pkoeppe

+0

Si COLUMN_1 et COLUMN_2 contiennent des données purement numériques, pourquoi transmettez-vous les opérandes sous forme de chaînes? – APC

+0

De même, où obtenez-vous les valeurs cibles pour COLUMN_1 et COLUMN_2? Êtes-vous vraiment en train d'assembler dynamiquement vos instructions SELECT? Que se passe-t-il vraiment ici? – APC

+0

Les colonnes sont de type char. – pkoeppe

Répondre

0

Pourriez-vous faire une modification à la variante 2 qui

  • défini un curseur
  • en vrac recueilli 100 lignes (par exemple) dans une table pl/sql
  • faire votre traitement
  • chercher les 100 prochaines rangées

Par exemple, voir http://oracletoday.blogspot.com/2005/11/bulk-collect_15.html

J'ai eu un problème très semblable à celui avec Oracle et Informix.

+0

Je pense que la question est centrée sur la sélection de choses dans la base de données DB2 plutôt que dans Oracle. – APC

+0

J'utilise maintenant la variante 2 et crée des clusters pour 100 objets.Pour chaque cluster, je demande le DB et place le résultat dans un DataTable pour tous les clusters via DataTable.Merge. Merci pour vos biches. – pkoeppe

+0

Heureux que vous l'ayez fait à la fin :-) –

0

Les deux variantes 2 et 3 sont saines. 1 n'est pas sain d'esprit.
Comme l'ID de colonne calculé dans 1 n'est dans aucun index, le DB sera forcé de faire au moins un balayage d'index complet. Dans 2 et 3, la base de données peut utiliser des index sur column1 et column2 pour filtrer le résultat.

Pour savoir si 2 ou 3 sont les meilleurs, vous devez étudier les plans d'exécution pour ces requêtes.

Une note de plus sur les index. Les index pertinents seront beaucoup plus importants que la différence entre 2 et 3. Même si vous n'avez que des droits sélectionnés, vous pouvez peut-être suggérer un index composite sur (colonne1, colonne2) à l'administrateur de base de données s'il n'existe pas déjà.

Modifier
Une autre approche commune lorsque vous avez beaucoup de valeurs dans WHERE COL IN (...) est de créer une table temporaire (si vous avez la permission) avec toutes les valeurs et se joindre à cette table temporaire à la place. Parfois, vous devez également créer un index sur la table temporaire pour qu'elle fonctionne correctement.
Dans certains SGBD: s vous pouvez utiliser des paramètres de table plutôt que des tables temporaires, mais je ne trouve rien de pareil pour DB2.

+0

On peut espérer qu'une clé primaire possède déjà un index unique. – APC

+0

Les index sont définis pour chaque colonne de la clé primaire. Je ne peux pas voir un index composite. – pkoeppe

+0

+1 La concaténation de deux colonnes et la recherche de celles-ci ajoutent des opérations supplémentaires à votre requête et entraînent toujours des performances plus lentes. –

0

SQL0954C peut être résolu en modifiant la configuration de votre système. Avez-vous déjà exploré cette avenue? Find out more.

+0

N'est-ce pas pour le côté serveur de la base de données? Je n'ai que des droits SELECT sur celui-ci. Et les gars de la base de données ne changeront rien. – pkoeppe

+0

Obtenir SQL0954C est quelque chose que les administrateurs de base de données devraient être prêts à corriger, à moins que votre requête ne fasse quelque chose de ridicule. Obtenez-vous l'erreur SQL0954C avec l'instruction exactement comme écrit? Ou fournissez-vous des centaines d'entrées dans votre clause where? –

0

Pour la variante 3, changer

SELECT COLUMN1, COLUMN2, COLUMN3, ..., COLUMN1||'_'||COLUMN2 AS ID 
FROM TABLE1 
WHERE COLUMN1 IN ('2011') 
AND COLUMN2 IN ('123456','987654') 

Pour:

SELECT COLUMN1, COLUMN2, COLUMN3, ..., COLUMN1||'_'||COLUMN2 AS ID 
FROM TABLE1 
WHERE COLUMN1 ='2011' 
AND COLUMN2 IN ('123456','987654') 

Si vous ne la recherche d'une valeur pour COLUMN1 il n'y a aucune raison d'utiliser IN.