Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como posso definir uma expressão para a propriedade FileSpec no enumerador de arquivo Foreach?


Ao investigar como o loop ForEach funciona no SSIS (com vistas a criar o meu próprio para resolver o problema), parece que a maneira como ele funciona (até onde eu pude ver) é enumerar a coleção de arquivos primeiro, antes que qualquer máscara seja Especificadas. É difícil dizer exatamente o que está acontecendo sem ver o código subjacente do loop ForEach, mas parece estar fazendo isso dessa maneira, resultando em desempenho lento ao lidar com mais de 100 mil arquivos.

Embora a solução do @Siva seja fantasticamente detalhada e definitivamente uma melhoria em relação à minha abordagem inicial, é essencialmente o mesmo processo, exceto usar uma tarefa de expressão para testar o nome do arquivo, em vez de uma tarefa de script (isso parece oferecer alguma melhoria).

Então, decidi adotar uma abordagem totalmente diferente e, em vez de usar um loop ForEach baseado em arquivo, enumerar a coleção eu mesmo em uma Tarefa de Script, aplicar minha lógica de filtragem e, em seguida, iterar sobre os resultados restantes. Isto é o que eu fiz:



Na minha Tarefa de Script, uso o DirectoryInfo.EnumerateFiles assíncrono método, que é a abordagem recomendada para grandes coleções de arquivos, pois permite streaming, em vez de ter que esperar que toda a coleção seja criada antes de aplicar qualquer lógica.

Aqui está o código:
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;
}

Então, enumero a coleção, aplicando minha lógica à medida que os arquivos são descobertos e adicionando imediatamente o caminho do arquivo à minha lista para saída. Depois de concluído, atribuo isso a uma variável de objeto SSIS chamada ActiveFilenames que usarei como coleção para meu loop ForEach.

Configurei o loop ForEach como um ForEach From Variable Enumerator , que agora itera em uma coleção muito menor (Pós-filtrado List<string> comparado com o que só posso supor que foi um List<FileInfo> não filtrado ou algo semelhante no ForEach File Enumerator integrado do SSIS .

Portanto, as tarefas dentro do meu loop podem ser dedicadas apenas ao processamento dos dados, pois já foram filtrados antes de entrar no loop. Embora não pareça estar fazendo muito diferente do meu pacote inicial ou do exemplo de Siva, na produção (para este caso em particular, de qualquer maneira) parece que filtrar a coleção e enumerar de forma assíncrona fornece um grande impulso sobre o uso do arquivo ForEach embutido Enumerador.

Vou continuar investigando o contêiner de loop ForEach e ver se consigo replicar essa lógica em um componente personalizado. Se eu conseguir isso, postarei um link nos comentários.