Dari menyelidiki bagaimana loop ForEach bekerja di SSIS (dengan maksud untuk membuat milik saya sendiri untuk menyelesaikan masalah) tampaknya cara kerjanya (sejauh yang saya bisa lihat) adalah dengan menghitung koleksi file terlebih dahulu, sebelum topeng apa pun adalah ditentukan. Sulit untuk mengetahui dengan tepat apa yang terjadi tanpa melihat kode yang mendasari untuk loop ForEach tetapi tampaknya melakukannya dengan cara ini, menghasilkan kinerja yang lambat saat menangani lebih dari 100 ribu file.
Sementara solusi @Siva sangat rinci dan jelas merupakan peningkatan dari pendekatan awal saya, pada dasarnya hanya proses yang sama, kecuali menggunakan Tugas Ekspresi untuk menguji nama file, daripada Tugas Skrip (ini tampaknya menawarkan beberapa peningkatan).
Jadi, saya memutuskan untuk mengambil pendekatan yang sama sekali berbeda dan daripada menggunakan loop ForEach berbasis file, menghitung koleksi sendiri dalam Tugas Skrip, menerapkan logika pemfilteran saya, dan kemudian mengulangi hasil yang tersisa. Inilah yang saya lakukan:
Dalam Tugas Skrip saya, saya menggunakan DirectoryInfo.EnumerateFiles
asinkron metode, yang merupakan pendekatan yang disarankan untuk koleksi file besar, karena memungkinkan streaming, daripada harus menunggu seluruh koleksi dibuat sebelum menerapkan logika apa pun.
Ini kodenya:
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;
}
Jadi, saya menghitung koleksi, menerapkan logika saya saat file ditemukan dan segera menambahkan jalur file ke daftar saya untuk output. Setelah selesai, saya kemudian menetapkan ini ke variabel Objek SSIS bernama ActiveFilenames yang akan saya gunakan sebagai koleksi untuk loop ForEach saya.
Saya mengonfigurasi loop ForEach sebagai ForEach From Variable Enumerator , yang sekarang mengulangi koleksi yang jauh lebih kecil (List<string>
yang difilter pasca-filter dibandingkan dengan apa yang hanya bisa saya asumsikan sebagai List<FileInfo>
. yang tidak difilter atau yang serupa di ForEach File Enumerator bawaan SSIS .
Jadi tugas di dalam loop saya hanya dapat didedikasikan untuk memproses data, karena sudah difilter sebelum mengenai loop. Meskipun tampaknya tidak jauh berbeda dengan paket awal saya atau contoh Siva, dalam produksi (untuk kasus khusus ini, bagaimanapun) sepertinya memfilter koleksi dan menghitung secara tidak sinkron memberikan dorongan besar untuk menggunakan File ForEach bawaan Pencacah.
Saya akan terus menyelidiki wadah loop ForEach dan melihat apakah saya dapat mereplikasi logika ini dalam komponen khusus. Jika saya berhasil, saya akan memposting tautan di komentar.