sql >> データベース >  >> RDS >> Sqlserver

Foreach File 列挙子の FileSpec プロパティに式を設定するにはどうすればよいですか?

    ForEach ループが SSIS でどのように機能するかを調査することから (問題を解決するために独自のループを作成することを目的として)、それが機能する方法は (とにかく見ることができる限り)、マスクが処理される前に、最初にファイル コレクションを列挙することのようです。指定。 ForEach ループの基礎となるコードを見ずに何が起こっているのかを正確に判断するのは困難ですが、このように実行しているようで、100k を超えるファイルを処理するとパフォーマンスが低下します。

    @Sivaのソリューションは非常に詳細で、私の最初のアプローチよりも確実に改善されていますが、スクリプトタスクではなく式タスクを使用してファイル名をテストすることを除いて、本質的に同じプロセスです(これはいくつかの改善を提供するようです)。 /P>

    そこで、ファイルベースの ForEach ループを使用するのではなく、スクリプト タスクで自分でコレクションを列挙し、フィルタリング ロジックを適用して、残りの結果を反復処理するという、まったく異なるアプローチを取ることにしました。これは私がしたことです:

    私のスクリプト タスクでは、非同期の DirectoryInfo.EnumerateFiles を使用します。 この方法は、ロジックを適用する前にコレクション全体が作成されるのを待つ必要がなく、ストリーミングが可能であるため、大規模なファイル コレクションに推奨されるアプローチです。

    コードは次のとおりです:

    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;
    }
    

    そのため、コレクションを列挙し、ファイルが検出されたときにロジックを適用し、すぐにファイル パスをリストに追加して出力します。完了したら、これを ActiveFilenames という名前の SSIS オブジェクト変数に割り当てます これを ForEach ループのコレクションとして使用します。

    ForEach ループを ForEach From Variable Enumerator として構成しました 、これははるかに小さなコレクションを反復するようになりました (Post-filtered List<string> フィルタリングされていない List<FileInfo> としか思えないものと比較して または、SSIS のビルトイン ForEach File Enumerator に似たもの .

    したがって、ループ内のタスクは、ループに入る前に既にフィルター処理されているため、データの処理に専念できます。私の最初のパッケージまたは Siva の例と大差ないように見えますが、実稼働環境では (とにかくこの特定のケースでは)、コレクションをフィルタリングし、非同期的に列挙することで、組み込みの ForEach File を使用するよりも大幅なブーストが得られるようです。列挙子。

    ForEach ループ コンテナーの調査を続け、このロジックをカスタム コンポーネントで複製できるかどうかを確認します。これが機能するようになったら、コメントにリンクを投稿します。



    1. 列が存在しないことを訴えるPostgreSQLのcurrval関数

    2. 特定の文字列値の前後の行を検索するにはどうすればよいですか?

    3. 作業単位のクローンでJPANullまたはゼロの主キーが検出されました

    4. 3列のORACLE10gでの文字列集約