Từ việc điều tra cách thức hoạt động của vòng lặp ForEach trong SSIS (với mục đích tạo của riêng tôi để giải quyết vấn đề), có vẻ như cách nó hoạt động (theo như tôi có thể thấy) là liệt kê bộ sưu tập tệp trước, trước khi bất kỳ mặt nạ nào. được chỉ định. Thật khó để nói chính xác điều gì đang xảy ra nếu không nhìn thấy mã cơ bản cho vòng lặp ForEach nhưng có vẻ như nó đang làm theo cách này, dẫn đến hiệu suất chậm khi xử lý hơn 100 nghìn tệp.
Mặc dù giải pháp của @ Siva rất chi tiết và chắc chắn là một cải tiến so với cách tiếp cận ban đầu của tôi, nhưng về cơ bản nó chỉ là cùng một quy trình, ngoại trừ việc sử dụng Nhiệm vụ biểu thức để kiểm tra tên tệp, thay vì Nhiệm vụ tập lệnh (điều này dường như mang lại một số cải tiến).
Vì vậy, tôi đã quyết định thực hiện một cách tiếp cận hoàn toàn khác và thay vì sử dụng vòng lặp ForEach dựa trên tệp, hãy tự liệt kê bộ sưu tập trong Tác vụ tập lệnh, áp dụng logic lọc của mình và sau đó lặp lại các kết quả còn lại. Đây là những gì tôi đã làm:
Trong Tác vụ tập lệnh của tôi, tôi sử dụng DirectoryInfo.EnumerateFiles
không đồng bộ , đây là phương pháp được đề xuất cho các tập hợp tệp lớn, vì nó cho phép truyền trực tuyến, thay vì phải đợi toàn bộ tập hợp được tạo trước khi áp dụng bất kỳ logic nào.
Đây là mã:
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;
}
Vì vậy, tôi liệt kê bộ sưu tập, áp dụng logic của tôi khi các tệp được phát hiện và ngay lập tức thêm đường dẫn tệp vào danh sách của tôi để xuất. Sau khi hoàn tất, tôi gán điều này cho một biến Đối tượng SSIS có tên là ActiveFilenames mà tôi sẽ sử dụng làm bộ sưu tập cho vòng lặp ForEach của mình.
Tôi đã định cấu hình vòng lặp ForEach dưới dạng ForEach From Variable Enumerator , hiện lặp lại trên một tập hợp nhỏ hơn nhiều (List<string>
được lọc sau so với những gì tôi chỉ có thể giả định là một List<FileInfo>
chưa được lọc hoặc thứ gì đó tương tự trong ForEach File Enumerator tích hợp sẵn của SSIS .
Vì vậy, các tác vụ bên trong vòng lặp của tôi chỉ có thể được dành riêng để xử lý dữ liệu, vì nó đã được lọc trước khi thực hiện vòng lặp. Mặc dù nó có vẻ không khác gì nhiều so với gói ban đầu của tôi hoặc ví dụ của Siva, nhưng trong sản xuất (dù sao thì đối với trường hợp cụ thể này), có vẻ như việc lọc bộ sưu tập và liệt kê không đồng bộ cung cấp một sự thúc đẩy lớn so với việc sử dụng ForEach File được tích hợp sẵn Điều tra viên.
Tôi sẽ tiếp tục điều tra vùng chứa vòng lặp ForEach và xem liệu tôi có thể sao chép logic này trong một thành phần tùy chỉnh hay không. Nếu tôi làm được điều này, tôi sẽ đăng một liên kết trong phần bình luận.