2010-08-25 9 views
1

Je parcourt toutes mes bases de données et agrège les résultats dans une base de données d'agrégats.tsql Boucle avec requête externe

Dans ma boucle j'appelle

master.dbo.xp_cmdshell osql C:\whatever.SQL 

Comme la boucle progresse, le cmdshell prend plus de temps et plus de temps à exécuter. Si j'arrête la boucle et exécute un agrégat unique pour une base de données, il s'exécute rapidement.

Y a-t-il quelque chose que je puisse ajouter à mon script SQL externe pour le faire fonctionner plus rapidement? Peut-être quelque chose à commettre et libérer les disques avant la prochaine boucle? Ou devrais-je ajouter une sorte de pause après chaque boucle?

Je souhaite utiliser un fichier SQL externe car il contient de nombreuses instructions de mise à jour, ce qui me permet de le gérer plus facilement.

Voici comment je boucle:

 
Update dbFoo.dbo.tblBar set Processed = 0 
Go 

WHILE EXISTS (SELECT ID FROM dbFoo.dbo.tblBar WHERE Processed = 0) 
    BEGIN 

     SELECT @aRow = MIN(tblBar.ID) FROM dbFoo.dbo.tblBar 
     SELECT @aFoo1 = Foo1 FROM dbFoo.dbo.tblBar WHERE ID = @aRow 
     SELECT @aFoo2 = Foo2 FROM dbFoo.dbo.tblBar WHERE ID = @aRow 
     SELECT @aFoo3 = Foo3 FROM dbFoo.dbo.tblWhatever WHERE Foo = @aFoo 

     EXEC RunPreAgg @Foo1 = @aFoo1, @Foo2 = @aFoo2, @Foo3 = @aFoo3, @RetVal = @aRetVal OUTPUT 
     SELECT returning = @aRetVal 

     UPDATE dbFoo.dbo.tblBar SET Processed = 1 WHERE ID = @aRow 
    END 

Ensuite, la procédure stockée RunPreAgg fait essentiellement ceci:

if db_id('db' + @Foo1 + '_' + @Foo2) is not null 
    BEGIN 
     --This bat file creates the SQL File 
     select @sql = 'master.dbo.xp_cmdshell '''[email protected]+'wwwRunPreAgg.bat ' + @Foo1 + ' ' + @Foo2 + ' ' + @Foo3 + '''' 
     exec(@sql) 

     --execute 
     select @sql = 'master.dbo.xp_cmdshell ''osql -E -o '[email protected]+'output\tmp'[email protected]+'_'[email protected]+'.txt -i '[email protected]+'tmp' + @Foo1 + '.SQL''' 
     exec(@sql) 

     --This erases the SQL File 
     select @sql = 'master.dbo.xp_cmdshell '''[email protected]+'wwwCleanup.bat ' + @Foo1 + ' ' + @Foo2 + '''' 
     exec(@sql) 

     Set @retval = 'Done!' 
    END 
ELSE 
    BEGIN 
     Set @retval = 'Err: No DataBase' 
    END 

Les noms de variables sont changés pour protéger les innocents. Le code fonctionne bien, j'ai juste besoin d'optimiser.

+0

peut-être vous devriez poster comment votre boucle à travers les bases de données? – DForck42

+0

ok j'ai ajouté mon code en boucle – shitburg

Répondre

0

Si les performances des boucles vous causent des problèmes, vous pouvez essayer de réduire le nombre de sélections. Normalement, je n'aime pas les curseurs, mais votre boucle pourrait en bénéficier. Vous pouvez sélectionner toutes les valeurs dont vous avez besoin pour la boucle en mémoire, puis faire défiler ces valeurs sans avoir à exécuter 3 ou 4 sélections par boucle (bien sûr, si le coup de performance se produit dans RunPreAgg SP, cela n'aidera pas) :

DECLARE cFoos CURSOR FOR 
    SELECT tblBar.ID, tblBar.Foo1, tblBar.Foo2, tblWhatever.Foo3 
    FROM dbFoo.dbo.tblBar 
     INNER JOIN dbFoo.dbo.tblWhatever 
      ON tblWhatever.Foo = tblBar.Foo 
    WHERE tblBar.Processed = 0; 

OPEN cFoos; 
FETCH NEXT FROM cFoos INTO @aRow, @aFoo1, @aFoo2, @aFoo3; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    EXEC RunPreAgg @Foo1 = @aFoo1, @Foo2 = @aFoo2, @Foo3 = @aFoo3, @RetVal = @aRetVal OUTPUT 
    SELECT returning = @aRetVal 

    UPDATE dbFoo.dbo.tblBar SET Processed = 1 WHERE ID = @aRow 

    FETCH NEXT FROM cFoos INTO @aRow, @Foo1, @Foo2, @Foo3; 
END 

CLOSE cFoos; 
DEALLOCATE cFoos; 
+0

Je me sens comme un doofus ... Il s'avère que c'était RunPreAgg, il me manquait toutes sortes d'index. Je vais utiliser votre code de boucle pour une optimisation plus poussée. Merci – shitburg