Ze zkoumání, jak funguje smyčka ForEach v SSIS (s ohledem na vytvoření mé vlastní k vyřešení problému), se zdá, že způsob, jakým to funguje (pokud jsem stejně viděl), je nejprve vyjmenovat kolekci souborů, než je jakákoli maska specifikováno. Je těžké přesně říct, co se děje, aniž byste viděli základní kód pro smyčku ForEach, ale zdá se, že to dělá tímto způsobem, což má za následek pomalý výkon při práci s více než 100 000 soubory.
I když je řešení @Siva fantasticky podrobné a rozhodně jde o zlepšení oproti mému původnímu přístupu, je to v podstatě stejný proces, s výjimkou použití Expression Task k testování názvu souboru, spíše než Script Task (zdá se, že to nabízí určité zlepšení).
Rozhodl jsem se tedy zaujmout zcela odlišný přístup a namísto použití smyčky ForEach založené na souborech, vyčíslit kolekci sám v úloze skriptu, použít svou logiku filtrování a poté iterovat zbývající výsledky. To je to, co jsem udělal:
Ve své úloze skriptu používám asynchronní DirectoryInfo.EnumerateFiles
metoda, která je doporučeným přístupem pro velké kolekce souborů, protože umožňuje streamování, spíše než čekat na vytvoření celé kolekce, než použijete jakoukoli logiku.
Zde je kód:
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;
}
Takže vyjmenuji kolekci, použiji svou logiku, když jsou soubory objeveny, a okamžitě přidám cestu k souboru do svého seznamu pro výstup. Po dokončení to přiřadím proměnné objektu SSIS s názvem ActiveFilenames kterou použiji jako kolekci pro svou smyčku ForEach.
Smyčku ForEach jsem nakonfiguroval jako ForEach From Variable Enumerator , který nyní iteruje přes mnohem menší kolekci (dodatečně filtrovaný List<string>
ve srovnání s tím, co mohu pouze předpokládat, byl nefiltrovaný List<FileInfo>
nebo něco podobného v SSIS vestavěném ForEach File Enumerator .
Takže úkoly v mé smyčce mohou být vyhrazeny pouze zpracování dat, protože ta již byla filtrována před tím, než zasáhla smyčku. Ačkoli se zdá, že se příliš neliší od mého původního balíčku nebo příkladu Siva, ve výrobě (pro tento konkrétní případ, každopádně) se zdá, že filtrování kolekce a asynchronní výčet poskytuje masivní podporu oproti použití vestavěného souboru ForEach File Enumerátor.
Budu pokračovat ve zkoumání kontejneru smyčky ForEach a uvidíme, zda mohu replikovat tuto logiku ve vlastní komponentě. Pokud se mi to podaří, vložím odkaz do komentářů.