Tại sao SSIS chậm liệt kê nhiều tệp trong một thư mục và nhập chúng?


7

Tôi có gói SSIS cực kỳ chậm. Nó khá nhanh với một tệp và khá nhanh với 100 tệp hoặc ít hơn. (Khoảng một giây mỗi tệp)

Tuy nhiên, nếu thư mục của tôi có hàng ngàn tệp (rất nhỏ), quá trình này kéo dài rất chậm. Sở thích của tôi là chỉ chạy quy trình này sau giờ làm việc, nhưng bằng cách đợi đến lúc đó, số lượng tệp phẳng cần nhập là hàng ngàn.

Gói rất đơn giản:

  • Vòng lặp ngoài là cho mọi (liệt kê tệp, đọc đường dẫn tệp thành biến)
  • Bên trong, chỉ cần nhập mà không có bất kỳ chuyển đổi nào cho dữ liệu

Thế là xong.

Hiệu suất với hàng ngàn tệp đang chạy 15 giây trở lên cho mỗi tệp. Giao diện người dùng (trạng thái) đang vẽ / cuộn chậm đến mức tôi thậm chí không thể nhìn thấy nó ở đâu - thời gian được đóng dấu là hơn 15 giờ trên một thực thi đã được bắt đầu 18 giờ trước.

Phiên bản: MSSQL 2012


2
Bạn đã làm bất cứ điều gì với TransactionOption (mặc định được hỗ trợ) trong gói chưa?
billinkc

1
Chúng tôi đã có một câu hỏi tương tự về việc SO SSIS xử lý số lượng lớn các tệp phẳng rất chậm nhưng thật đáng buồn, không có độ phân giải
billinkc

2
Có thể rất thú vị khi vô hiệu hóa phần dataflow và chỉ cần xem trình liệt kê foreach mất bao lâu để quay qua tất cả các tệp đó. Tôi mong đợi nó linh hoạt
billinkc

1
Có thể một đề xuất đã thử, nhưng di chuyển các tệp trong các thư mục được đánh số (mỗi tệp có 100 tệp) và xử lý từng tệp một.
Mary

1
Có bằng chứng nào hỗ trợ cho giả định rằng số lượng tệp là vấn đề không? Quá trình này làm gì với các tập tin? Bạn đang chèn dữ liệu vào một đống ngày càng tăng hoặc liên tục phân đoạn bảng cụm?
Mark Storey-Smith

Câu trả lời:


9

Tôi nghĩ rằng bạn đang chạy vào một giới hạn của UI / trình gỡ lỗi.

Tôi đã tạo hai gói: MakeAllTheFiles và ReadAllTheFiles

MakeAllTheFiles chấp nhận làm đầu vào số lượng tệp sẽ được tạo. Nó sẽ sử dụng hàm giả ngẫu nhiên để phân phối dữ liệu qua một số (7) thư mục con.

Make ALLTheFiles

    public void Main()
    {
        int NumberOfFilesToGenerate = (Int32)Dts.Variables["User::FilesToGenerate"].Value;
        string baseFolder = Dts.Variables["User::FolderInput"].Value.ToString();
        System.Random rand = null;
        int fileRows = 0;
        DateTime current = DateTime.Now;
        int currentRandom = -1;
        int seed = 0;
        string folder = string.Empty;
        string currentFile = string.Empty;

        for (int i = 0; i < NumberOfFilesToGenerate; i++)
        {
            seed = i * current.Month * current.Day * current.Hour * current.Minute * current.Second;
            rand = new Random(seed);
            currentRandom = rand.Next();

            // Create files in sub folders
            folder = System.IO.Path.Combine(baseFolder, string.Format("f_{0}", currentRandom % 7));

            // Create the folder if it does not exist
            if (!System.IO.Directory.Exists(folder))
            {
                System.IO.Directory.CreateDirectory(folder);
            }

            currentFile = System.IO.Path.Combine(folder, string.Format("input_{0}.txt", currentRandom));

            System.IO.FileInfo f = new FileInfo(currentFile);
            using (System.IO.StreamWriter writer = f.CreateText())
            {
                int upperBound = rand.Next(50);
                for (int row = 0; row < upperBound; row++)
                {
                    if (row == 0)
                    {
                        writer.WriteLine(string.Format("{0}|{1}", "Col1", "Col2"));                        }

                    writer.WriteLine(string.Format("{0}|{1}", row, seed));
                }
            }
            ;
        }
        Dts.TaskResult = (int)ScriptResults.Success;
    }

Read ALLTheFiles

Sự xuất hiện chung của gói là như vậy

Đọc tất cả các tập tin!

Tôi có hai Trình quản lý kết nối được xác định: Một là cho cơ sở dữ liệu của tôi và hai là cho một tệp phẳng có biểu thức trên thuộc tính ConnectionString sao cho nó sử dụng Biến của tôi @[User::CurrentFileName]

Biến, tôi thích rất nhiều biến nên có rất nhiều.

nhập mô tả hình ảnh ở đây

Nhiệm vụ SQL thực thi của tôi chỉ đơn giản là đứng lên một bảng để tôi viết, gõ nó xuống nếu nó đã tồn tại.

IF EXISTS
(
    SELECT * FROM sys.tables AS T WHERE T.name = 'dbase_54462' AND T.schema_id = SCHEMA_ID('dbo')
)
BEGIN
    DROP TABLE dbo.dbase_54462;
END

CREATE TABLE
    dbo.dbase_54462
(
    CurrentFile varchar(256) NOT NULL
,   Col1 int NOT NULL
,   Col2 varchar(50) NOT NULL
,   InsertDate datetime NOT NULL DEFAULT(CURRENT_TIMESTAMP)
);

Trình liệt kê Foreach của tôi chỉ đơn giản là xem xét mọi thứ trong thư mục Nhập của tôi dựa trên mặt nạ tệp của * .txt và duyệt qua các thư mục con. Tên tệp hiện tại được gán cho biến của tôi @ [User :: CurrentFileName] `

nhập mô tả hình ảnh ở đây

Luồng dữ liệu là tiêu chuẩn không có thật. Chuyển đổi cột có nguồn gốc ở đó chỉ cần thêm biến Tên tệp hiện tại vào luồng dữ liệu để tôi có thể ghi lại trong bảng.

nhập mô tả hình ảnh ở đây

Phân tích

Tôi lười biếng và không muốn làm gì đặc biệt để ghi lại thời gian xử lý nên tôi đã triển khai các gói của mình vào danh mục SSISDB và chạy chúng từ đó.

Truy vấn này xem xét dữ liệu danh mục để tìm hiểu gói đã chạy trong bao lâu, bao nhiêu tệp được xử lý và sau đó tạo trung bình chạy cho số lượng tệp. Chạy 10047 là xấu và đã bị loại khỏi phân tích.

SELECT
    E.execution_id
,   DATEDIFF(s, E.start_time, E.end_time) As duration_s
,   ES.rc AS FilesProcessed
,   AVG(ES.rc / (1.0 * DATEDIFF(s, E.start_time, E.end_time))) OVER (PARTITION BY ES.rc ORDER BY E.execution_id) AS running_average
FROM
    catalog.executions As E
    INNER JOIN
    (
        SELECT
            MIN(ES.start_time) As start_time
        ,   MAX(ES.end_time) AS end_time
        ,   count(1) As rc
        ,   ES.execution_id
        FROm
            catalog.executable_statistics AS ES
        GROUP BY
            ES.execution_id
    ) AS ES 
    ON ES.execution_id = E.execution_id
WHERE
    E.package_name = 'ReadAllTheFiles.dtsx'
    AND E.execution_id <> 10047
ORDER BY 1,2

Dữ liệu kết quả ( SQLFiddle vô cớ )

execution_id    duration_s  FilesProcessed  running_average
10043   15  104 6.93333333333333
10044   13  104 7.46666666666666
10045   13  104 7.64444444444444
10050   102 1004    9.84313725490196
10051   101 1004    9.89186565715395
10052   102 1004    9.87562285640328
10053   106 1004    9.77464167060435
10055   1103    10004   9.06980961015412
10056   1065    10004   9.23161842010053
10057   1033    10004   9.38255038913446
10058   957 10004   9.65028792246735
10059   945 10004   9.83747901522255

Dựa trên kích thước lấy mẫu này, tôi thấy không có sự khác biệt đáng kể nào giữa việc xử lý 100, 1000 hoặc 10.000 tệp với SSIS như được mô tả trong tài liệu này.

Giả định nguyên nhân gốc rễ

Dựa trên nhận xét về DTExecUI.exeviệc cho biết bạn đang chạy gói từ bên trong Visual Studio (BIDS / SSDT / tên của tuần). Để có được những thay đổi màu sắc đẹp và khả năng sửa lỗi, thực thi gốc (dtexec.exe) được gói gọn trong quá trình gỡ lỗi. Điều đó tạo ra một lực cản đáng kể trong việc thực hiện.

Sử dụng môi trường thiết kế để tạo các gói của bạn và để chạy chúng cho các tập dữ liệu nhỏ hơn. Những cái lớn hơn được xử lý tốt nhất thông qua các giao diện thực thi phi đồ họa và không gỡ lỗi (shift-F5 trong VS, triển khai vào danh mục SSIS và thực thi từ đó, hoặc chuyển sang giao diện dòng lệnh và sử dụng dtutil.exe)


Tôi thách thức câu nói của bạn: "Tôi lười biếng." Dường như với tôi bạn không phải. Câu trả lời chính xác. Tôi đã từ bỏ nhiệm vụ này để thay thế SSIS bằng Quy trình lưu trữ CLR đang hút thuốc nhanh (như tôi nghi ngờ sẽ xảy ra nếu tôi triển khai như bạn đề xuất trong đoạn kết thúc của bạn). Cảm ơn bạn cho một câu trả lời rõ ràng như vậy!
Chris Adragna
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.