2010-03-11 9 views
2

Je dois sélectionner les données d'une table et l'insérer dans une autre table. Actuellement, le SQL ressemble à ceci:SELECT seulement un certain nombre de lignes à la fois

INSERT INTO A (x, y, z) 
    SELECT x, y, z 
    FROM B b 
    WHERE ... 

Cependant, le SELECT est énorme, ce qui entraîne dans plus de 2 millions de lignes et nous pensons qu'il prend trop de mémoire. Informix, la base de données dans ce cas, ne dispose plus de mémoire virtuelle lors de l'exécution de la requête.

Comment procéder pour sélectionner et insérer un ensemble de lignes (disons 2000)? Étant donné que je ne pense pas qu'il y ait des identifiants de ligne, etc.

+0

Essayez «FIRST»; 'LIMIT' est un synonyme supporté 10+: http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.docnotes.doc/uc3/ids_sqlt_docnotes_10.0.html –

+0

Oui, et en le combinant avec 'skip' vous pouvez itérer sur tout l'ensemble dans une boucle .. (* si vous connaissez le nombre total de lignes *) –

+0

et si la table B change, ne courez pas le risque de sauter les lignes que vous n'avez pas copiées? Je sais que je n'ai pas mentionné que la table B peut changer, dans mon cas, ce ne sera probablement pas le cas, mais je ne fais que penser à haute voix ici. – rouble

Répondre

3

Vous pouvez faire SELECT FIRST n * à partir du tableau. Où n est la quantité de lignes que vous voulez, disons 2000. De plus, dans la clause WHERE, faites une sélection intégrée qui vérifie la table dans laquelle vous insérez des lignes déjà existantes. Ainsi, la prochaine fois que l'instruction sera exécutée, elle n'inclura pas les données déjà insérées.

+0

cela semble bien. Comment écririez-vous une boucle de sélection qui boucle jusqu'à ce que la sélection ne renvoie aucune ligne? – rouble

+0

utilisez la fonction NOT EXISTS pour vous assurer que la ligne que vous insérez n'existe pas déjà dans la nouvelle table. – northpole

0

Je suppose que vous avez un script à partir duquel il est exécuté? Vous pouvez simplement boucler et limiter tant que vous commandez les valeurs renvoyées par la sélection imbriquée. Voici un pseudo code.

total = SELECT COUNT(x) FROM B WHERE ... 
while (total > 0) 
    INSERT INTO A (x, y, z) SELECT x, y, z FROM B b WHERE ... ORDER BY x LIMIT 2000 
    total = total - 2000 
end 
0

Je suis presque certain que l'IDS vous permet d'utiliser uniquement la clause FIRST où les données sont renvoyées au client , et qui est quelque chose que vous voulez éviter, si possible.

Vous dites que vous obtenez une erreur de mémoire insuffisante (plutôt qu'une erreur de transaction longue, par exemple)? Avez-vous regardé la configuration de votre serveur pour vous assurer qu'il a une quantité raisonnable de mémoire?

Cela dépend en partie de la taille de votre ensemble de données et de ses contraintes, c'est-à-dire de la raison pour laquelle vous chargez les tables. Mais je chercherais normalement à déterminer un moyen de partitionner les données en sous-ensembles chargeables et de les exécuter séquentiellement dans une boucle. Par exemple, si les numéros de séquence sont entre 1 et 10.000.000, je pourrais exécuter la boucle dix fois, avec la condition sur le numéro de séquence pour AND seqnum >= 0 AND seqnum < 1000000' and then ET seqnum> = 1000000 et seqnum', etc. De préférence dans une langue avec la capacité de substituer la gamme par des variables. Ceci est un peu gênant, et vous voulez vous tromper sur le côté conservateur en termes de taille de gamme (plus petites partitions plutôt que moins grandes - pour réduire le risque de manquer de mémoire).


trop simplifier un peu. Une procédure stockée doit être considérée comme «client», par exemple, et le coût de communication dans une procédure stockée est (beaucoup) inférieur au coût d'accès au client authentique.

Questions connexes