sql >> Base de Datos >  >> RDS >> Sqlserver

¿Cómo puedo establecer una expresión en la propiedad FileSpec en el enumerador de archivos Foreach?

Al investigar cómo funciona el ciclo ForEach en SSIS (con miras a crear el mío propio para resolver el problema), parece que la forma en que funciona (por lo que pude ver de todos modos) es enumerar primero la colección de archivos, antes de que se aplique cualquier máscara. especificado. Es difícil saber exactamente qué está pasando sin ver el código subyacente del bucle ForEach, pero parece estar haciéndolo de esta manera, lo que resulta en un rendimiento lento cuando se trata de más de 100 000 archivos.

Si bien la solución de @Siva es fantásticamente detallada y definitivamente una mejora con respecto a mi enfoque inicial, es esencialmente el mismo proceso, excepto que se usa una tarea de expresión para probar el nombre del archivo, en lugar de una tarea de secuencia de comandos (esto parece ofrecer alguna mejora).

Entonces, decidí adoptar un enfoque totalmente diferente y, en lugar de usar un bucle ForEach basado en archivos, enumeré la colección yo mismo en una tarea de secuencia de comandos, apliqué mi lógica de filtrado y luego iteré sobre los resultados restantes. Esto es lo que hice:

En mi tarea de secuencia de comandos, uso el DirectoryInfo.EnumerateFiles asíncrono método, que es el enfoque recomendado para grandes colecciones de archivos, ya que permite la transmisión, en lugar de tener que esperar a que se cree toda la colección antes de aplicar cualquier lógica.

Aquí está el 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;
}

Entonces, enumero la colección, aplico mi lógica a medida que se descubren los archivos e inmediatamente agrego la ruta del archivo a mi lista para la salida. Una vez completado, lo asigno a una variable de objeto SSIS llamada ActiveFilenames que usaré como colección para mi bucle ForEach.

Configuré el ciclo ForEach como un ForEach From Variable Enumerator , que ahora itera sobre una colección mucho más pequeña (List<string> Post-filtered en comparación con lo que solo puedo suponer que era un List<FileInfo> sin filtrar o algo similar en el Enumerador de archivos ForEach incorporado de SSIS .

Por lo tanto, las tareas dentro de mi bucle solo pueden dedicarse a procesar los datos, ya que ya se han filtrado antes de entrar en el bucle. Aunque no parece estar funcionando de manera muy diferente a mi paquete inicial o al ejemplo de Siva, en producción (para este caso particular, de todos modos) parece que filtrar la colección y enumerar de forma asincrónica proporciona un gran impulso sobre el uso del archivo ForEach integrado. Enumerador.

Seguiré investigando el contenedor de bucles ForEach y veré si puedo replicar esta lógica en un componente personalizado. Si hago que esto funcione, publicaré un enlace en los comentarios.