Chạy các thủ tục được lưu trữ song song


9

Tôi đang tìm cách thử và chạy cùng một quy trình được lưu trữ nhiều lần với các tham số khác nhau nhưng cùng một lúc.

Tôi đang sử dụng SQL 2014

Lý do cho điều này là thủ tục mất khoảng 7 giờ để hoàn thành. Nó thực sự làm quá trình tương tự nhiều lần. Vì vậy, ví dụ, nó có thể xây dựng một cơ sở dữ liệu và bảng mới cho mỗi nhánh.

Những gì tôi muốn làm là phá vỡ các thủ tục được lưu trữ để tôi có thể chạy trong mỗi nhánh nhưng sau đó chạy từng truy vấn song song. Tôi đã chạy thử nghiệm điều này bằng cách chạy nó trong các cửa sổ truy vấn riêng biệt và nó chạy nhanh hơn gần 80%.

Bất cứ ai cũng có thể cho tôi một hướng dẫn giả để chạy các truy vấn song song?

Câu trả lời:


8

Tại một thời điểm tôi đã trả lời câu hỏi này tại StackOverflow , nhưng có vẻ như sẽ hữu ích khi có thông tin đó tại DBA.SE, được sửa đổi và cập nhật.

Hoàn toàn rõ ràng: TSQL không (tự nó) có khả năng khởi chạy các hoạt động TSQL khác không đồng bộ .

Điều đó không có nghĩa là bạn vẫn không có nhiều lựa chọn (một số trong số chúng được đề cập trong các câu trả lời khác):

  • Các công việc của Tác nhân SQL : Tạo nhiều công việc SQL và lên lịch cho chúng chạy vào thời gian mong muốn hoặc khởi động chúng không đồng bộ từ một "điều khiển chính" được lưu trữ bằng cách sử dụng sp_start_job. Nếu bạn cần theo dõi tiến trình của họ theo chương trình, chỉ cần đảm bảo mỗi công việc cập nhật bảng JOB_PROGRESS tùy chỉnh (hoặc bạn có thể kiểm tra xem họ đã hoàn thành chưa sử dụng chức năng không có giấy tờ xp_sqlagent_enum_jobsnhư được mô tả trong bài viết xuất sắc này của Gregory A. Larsen). Bạn phải tạo nhiều công việc riêng biệt như bạn muốn các quy trình song song đang chạy, ngay cả khi chúng đang chạy cùng một Proc được lưu trữ với các tham số khác nhau.
  • Gói SSIS : Tạo gói SSIS với luồng tác vụ phân nhánh đơn giản. SSIS sẽ khởi chạy các tác vụ đó trong các spids riêng lẻ, SQL sẽ thực thi song song.
  • Ứng dụng tùy chỉnh : Viết một ứng dụng tùy chỉnh đơn giản bằng ngôn ngữ bạn chọn (C #, Powershell, v.v.), sử dụng các phương thức không đồng bộ được cung cấp bởi ngôn ngữ đó. Gọi một SQL được lưu trữ trên mỗi luồng ứng dụng.
  • Tự động hóa OLE : Trong SQL, sử dụng sp_oacreatesp_oamethodđể khởi chạy một quy trình mới gọi nhau là Proc được lưu trữ như được mô tả trong bài viết này , cũng bởi Gregory A. Larsen.
  • Nhà môi giới dịch vụ : Xem xét việc sử dụng Nhà môi giới dịch vụ , một ví dụ điển hình về thực thi không đồng bộ trong bài viết này .
  • Thực thi song song CLR : Sử dụng các lệnh CLR Parallel_AddSqlParallel_Executenhư được mô tả trong bài viết này của Alan Kaplan (chỉ SQL2005 +).
  • Các tác vụ Windows được lên lịch : Được liệt kê để hoàn thiện, nhưng tôi không phải là người hâm mộ của tùy chọn này.

Nếu là tôi, có lẽ tôi sẽ sử dụng nhiều Công việc Tác nhân SQL trong các tình huống đơn giản hơn và gói SSIS trong các tình huống phức tạp hơn.

Trong trường hợp của bạn, trừ khi bạn đang cố gắng khởi chạy 200 luồng riêng biệt, nhiều công việc Đại lý theo lịch trình có vẻ như là một lựa chọn đơn giản và dễ quản lý.

Một nhận xét cuối cùng : SQL đã cố gắng song song hóa các hoạt động riêng lẻ bất cứ khi nào có thể *. Điều này có nghĩa là chạy 2 nhiệm vụ cùng một lúc thay vì sau nhau không đảm bảo rằng nó sẽ hoàn thành sớm hơn. Kiểm tra cẩn thận để xem liệu nó thực sự cải thiện bất cứ điều gì hay không.

Chúng tôi đã có một nhà phát triển tạo ra một gói DTS để chạy 8 nhiệm vụ cùng một lúc. Thật không may, nó chỉ là một máy chủ 4 CPU :)

* Giả sử cài đặt mặc định. Điều này có thể được sửa đổi bằng cách thay đổi Mức độ song song hoặc mặt nạ tối đa của máy chủ hoặc bằng cách sử dụng gợi ý truy vấn MAXDOP.


2

Đặt cược tốt nhất của bạn là tạo ra ba công việc riêng biệt với cùng một lịch trình để khởi động công việc cùng một lúc. Tùy thuộc vào những gì công việc đang làm, bạn nên cẩn thận để theo dõi chặn và bế tắc.

Một tùy chọn khác là tạo gói SSIS với N số toán tử để gọi SP song song


2

Bạn có thể sử dụng Powershell. Giả sử bạn đang làm việc với SQL Server, bạn có thể làm một cái gì đó như thế này: (đã được kiểm tra và dọn dẹp ngay bây giờ)

#This script creates a number of connections (one per entry in $Commands) 
# to a SQL Server instance ($Server) and database ($DBName)
#Driver variables


#Set Initial collections and objects    
$Server= "(local)\sql2016cs" ; #Server to connect to
$DBName = "Test" ; #Database to connect to

$Commands = @()
$Commands += "EXEC sp_LogMe 'a'"
$Commands += "EXEC sp_LogMe 'b'"

#Loop through commands array, create script block for establishing SMO connection/query
#Start-Job for each script block
foreach ($sql in $Commands ) {

# All of that extra information after "Smo" tells it to load just v12 (for when you have multiple
#   versions of SQL installed.)  Note: V13 is 2016.
 $cmdstr =@"
`Add-Type -AssemblyName "Microsoft.SqlServer.Smo,Version=$(13).0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91"
`[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
`$SqlConn = New-Object Microsoft.SqlServer.Management.Smo.Server ("$Server")
`$SqlConn.Databases["$DBName"].ExecuteNonQuery("$sql")
"@

#Uncomment the next like to print the command string for debugging
# $cmdstr
#Execute script block in jobs to run the command asyncronously
$cmd = [ScriptBlock]::Create($cmdstr)
Start-Job -ScriptBlock $cmd
}

Lưu ý: Tôi đã lấy cái này từ một cái gì đó tương tự tôi đã làm ở đây đã được thử nghiệm: https://sqlstudies.com/2016/02/24/powershell-script-to-create-multipl-sql-server-connections/

Trong đó tôi đã chạy một vòng lặp để tạo ra một loạt các lệnh làm điều tương tự. Tập lệnh này sử dụng khối tập lệnh để chạy từng lệnh không đồng bộ nhưng với các lệnh thực tế khác nhau. Để làm cho mọi thứ dễ dàng hơn, tôi đã đưa danh sách các lệnh bạn muốn chạy vào một mảng và lặp qua mảng đó.


1

Tôi sử dụng ứng dụng C # với đa luồng Parallel.ForEachđể gọi sp với các thông số khác nhau. Có ba phần. Ban đầu, cơ thể, địa phương Cuối cùng

public void NearLinkParallelGeneration(avl_range avl_pending, DateTime dt_start_process)
    {
        var parallelOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = Environment.ProcessorCount + 2
        };

        // create the partition based on the input
        var partitions = Partitioner
                            .Create(
                                fromInclusive: avl_pending.begin,
                                toExclusive: avl_pending.end,
                                rangeSize: 100
                            )
                            .GetDynamicPartitions();

        Parallel.ForEach(
            source: partitions,
            parallelOptions: parallelOptions,
            localInit: () =>
            {
                NpgsqlConnection conn = new NpgsqlConnection(strConnection);
                NpgsqlCommand cmd = new NpgsqlCommand();
                try
                {
                    conn.Open();
                    cmd.Connection = conn;
                    cmd.CommandText = "SELECT * FROM avl_db.process_near_link(@begin, @end, @start_time);";
                    cmd.CommandType = CommandType.Text;

                    NpgsqlParameter p = new NpgsqlParameter("@begin", NpgsqlDbType.Bigint);
                    cmd.Parameters.Add(p);

                    p = new NpgsqlParameter("@end", NpgsqlDbType.Bigint);
                    cmd.Parameters.Add(p);

                    p = new NpgsqlParameter("@start_time", NpgsqlDbType.Timestamp);
                    p.Value = dt_start_process;
                    cmd.Parameters.Add(p);
                }
                catch (NpgsqlException ex)
                {
                    Console.WriteLine(ex.InnerException);
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.InnerException);
                }

                return new { Connection = conn, Command = cmd };
            },
            body: (source, state, local) =>
            {
                if (local.Connection.State == ConnectionState.Open)
                {
                    string strResult = String.Format("From: {0} - To: {1}", source.Item1, source.Item2);
                    Console.WriteLine(strResult);

                    try
                    {
                        local.Command.Parameters["@begin"].Value = source.Item1;
                        local.Command.Parameters["@end"].Value = source.Item2;
                        local.Command.ExecuteNonQuery();
                    }
                    catch (NpgsqlException ex)
                    {
                        Console.WriteLine(ex.InnerException);
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.InnerException);
                    }

                    //strResult = String.Format("DONE From: {0} - To: {1}", source.Item1, source.Item2);
                    //Console.WriteLine(strResult);

                }
                return local;
            },
            localFinally: local =>
            {
                local.Command?.Dispose();
                local.Connection?.Dispose();
            }
        );
    }

1

Bạn cũng có thể sử dụng ForEach -Paralleltrong Powershell.

Ví dụ dưới đây (lấy từ câu hỏi của tôi Powershell Run Thủ tục lưu trữ song song trong cơ sở dữ liệu ) sẽ chạy tất cả các thủ tục được lưu trữ trong cơ sở dữ liệu:

Workflow TestRunParallelExecute
{
    $ServerName = "localhost"
    $DatabaseName = "testrun"
    $Procedure_Query = "select name from sys.procedures"
    $Procedure_List = (Invoke-Sqlcmd -Server $ServerName -Database $DatabaseName -Query $Procedure_Query)

    ForEach -Parallel ($Procedure in $Procedure_List.Name)
    {
         Invoke-Sqlcmd -Server $ServerName -Database $DatabaseName -Query $Procedure 
    }
}
TestRunParallelExecute
cls

0

Vì điều này nhắc nhở tôi về một trường hợp sử dụng mà tôi gặp phải trong công việc, tôi sẽ đưa ra cách chúng tôi giải quyết nó:

Đầu tiên như đã nói, tôi không nghĩ rằng bất kỳ kiểu "nohup" nào của Unix tồn tại trong SQL: one Connexion = one statement, với mọi thứ đi cùng (khóa, cam kết, lỗi ...)

Chúng tôi tìm cách sử dụng Talend ETL miễn phí, định cấu hình nó để kết nối với DB và chạy một loạt các công việc song song bao bọc thủ tục được lưu trữ.

Chúng tôi đã sử dụng Iteratethành phần và vòng lặp bao nhiêu lần chúng tôi cần, cho phép multi-threadstùy chọn.

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.