sql >> Database teknologi >  >> RDS >> Sqlserver

Hvordan kan jeg indstille et udtryk til egenskaben FileSpec på Foreach File Enumerator?

Fra at undersøge, hvordan ForEach-løkken fungerer i SSIS (med henblik på at skabe min egen for at løse problemet), ser det ud til, at den måde, det fungerer på (så vidt jeg i hvert fald kunne se), er at opregne filsamlingen først, før nogen maske er specificeret. Det er svært at sige præcist, hvad der foregår uden at se den underliggende kode for ForEach-løkken, men det ser ud til at gøre det på denne måde, hvilket resulterer i langsom ydeevne, når man håndterer over 100.000 filer.

Selvom @Sivas løsning er fantastisk detaljeret og absolut en forbedring i forhold til min oprindelige tilgang, er det i bund og grund bare den samme proces, bortset fra at bruge en udtryksopgave til at teste filnavnet i stedet for en scriptopgave (dette ser ud til at give en vis forbedring).

Så jeg besluttede at tage en helt anden tilgang og i stedet for at bruge en filbaseret ForEach-løkke, opregne samlingen selv i en scriptopgave, anvende min filtreringslogik og derefter gentage de resterende resultater. Dette er, hvad jeg gjorde:

I min scriptopgave bruger jeg den asynkrone DirectoryInfo.EnumerateFiles metode, som er den anbefalede tilgang til store filsamlinger, da den tillader streaming i stedet for at skulle vente på, at hele samlingen er oprettet, før der anvendes nogen logik.

Her er koden:

public void Main()
{
    string sourceDir = Dts.Variables["SourceDirectory"].Value.ToString();
    int minJobId = (int)Dts.Variables["MinIndexId"].Value;

    //Enumerate file collection (using Enumerate Files to allow us to start processing immediately
    List<string> activeFiles = new List<string>();

    System.Threading.Tasks.Task listTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
         DirectoryInfo dir = new DirectoryInfo(sourceDir);
         foreach (FileInfo f in dir.EnumerateFiles("*.txt"))
         {
              FileInfo file = f;
              string filePath = file.FullName;
              string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
              int jobId = Convert.ToInt32(fileName.Substring(0, fileName.IndexOf(".txt")));

              if (jobId > minJobId)
                   activeFiles.Add(filePath);
         }
    });

    //Wait here for completion
    System.Threading.Tasks.Task.WaitAll(new System.Threading.Tasks.Task[] { listTask });
    Dts.Variables["ActiveFilenames"].Value = activeFiles;
    Dts.TaskResult = (int)ScriptResults.Success;
}

Så jeg opregner samlingen, anvender min logik efterhånden som filer opdages og tilføjer straks filstien til min liste til output. Når jeg er færdig, tildeler jeg dette til en SSIS-objektvariabel ved navn ActiveFilenames som jeg vil bruge som samlingen til min ForEach-løkke.

Jeg konfigurerede ForEach-løkken som en ForEach From Variable Enumerator , som nu itererer over en meget mindre samling (efterfiltreret List<string> sammenlignet med hvad jeg kun kan antage var en ufiltreret List<FileInfo> eller noget lignende i SSIS' indbyggede ForEach File Enumerator .

Så opgaverne inde i min løkke kan bare dedikeres til at behandle dataene, da de allerede er blevet filtreret, før de rammer løkken. Selvom det ikke ser ud til at gøre meget anderledes end hverken min oprindelige pakke eller Sivas eksempel, i produktionen (i hvert fald i dette særlige tilfælde) ser det ud til, at filtrering af samlingen og asynkron optælling giver et massivt løft i forhold til at bruge den indbyggede ForEach File Enumerator.

Jeg vil fortsætte med at undersøge ForEach-løkkebeholderen og se, om jeg kan replikere denne logik i en tilpasset komponent. Hvis jeg får det til at virke, vil jeg poste et link i kommentarerne.



  1. tælle datoforskel i timer ved hjælp af php og mysql

  2. Hvordan får man outputparametre fra MySQL-lagret procedure i Rails?

  3. Anbefalet metode til at importere en .csv-fil til Microsoft SQL Server 2008 R2?

  4. Hvordan forbinder man R til Oracle?