Jalankan prosedur tersimpan secara paralel


9

Saya ingin mencoba dan menjalankan prosedur tersimpan yang sama beberapa kali dengan parameter berbeda tetapi pada saat yang sama.

Saya menggunakan SQL 2014

Alasan untuk ini adalah bahwa prosedur ini memakan waktu sekitar 7 jam untuk menyelesaikan. Ini sebenarnya melakukan proses yang sama berkali-kali. Jadi misalnya mungkin membangun database dan tabel baru untuk setiap cabang.

Yang ingin saya lakukan adalah memecah prosedur yang tersimpan sehingga saya bisa berjalan di per cabang tapi kemudian menjalankan setiap permintaan secara paralel. Saya sudah menjalankan ini dengan menjalankannya di jendela permintaan yang terpisah dan berjalan hampir 80% lebih cepat.

Adakah yang bisa memberi saya panduan boneka untuk menjalankan kueri secara paralel?

Jawaban:


8

Pada satu titik saya menjawab pertanyaan ini di StackOverflow , tetapi sepertinya akan berguna untuk memiliki informasi itu di DBA.SE juga, direvisi dan diperbarui.

Secara eksplisit: TSQL tidak (dengan sendirinya) memiliki kemampuan untuk meluncurkan operasi TSQL lainnya secara tidak sinkron .

Itu tidak berarti Anda masih tidak memiliki banyak opsi (beberapa di antaranya disebutkan dalam jawaban lain):

  • Pekerjaan SQL Agent : Buat beberapa pekerjaan SQL, dan jadwalkan untuk dijalankan pada waktu yang diinginkan, atau mulai secara asinkron dari "master control" yang disimpan menggunakan proc sp_start_job. Jika Anda perlu memantau progresnya secara programatik, pastikan masing-masing pekerjaan memperbarui tabel JOB_PROGRESS khusus (atau Anda dapat memeriksa apakah mereka telah selesai menggunakan fungsi tidak berdokumen xp_sqlagent_enum_jobsseperti dijelaskan dalam artikel yang sangat bagus ini oleh Gregory A. Larsen). Anda harus membuat pekerjaan terpisah sebanyak yang Anda inginkan untuk menjalankan proses paralel, bahkan jika mereka menjalankan proc tersimpan yang sama dengan parameter yang berbeda.
  • Paket SSIS : Buat paket SSIS dengan alur tugas percabangan yang sederhana. SSIS akan meluncurkan tugas-tugas tersebut dalam masing-masing spid, yang akan dieksekusi SQL secara paralel.
  • Aplikasi khusus : Tulis aplikasi kustom sederhana dalam bahasa pilihan Anda (C #, Powershell, dll), menggunakan metode asinkron yang disediakan oleh bahasa itu. Panggil proc tersimpan SQL di setiap utas aplikasi.
  • OLE Automation : Dalam SQL, gunakan sp_oacreatedan sp_oamethoduntuk meluncurkan proses baru memanggil masing-masing proc tersimpan lainnya seperti yang dijelaskan dalam artikel ini , juga oleh Gregory A. Larsen.
  • Pialang Layanan : Lihat ke dalam menggunakan Pialang Layanan , contoh yang baik dari eksekusi asinkron dalam artikel ini .
  • Eksekusi Paralel CLR : Gunakan perintah CLR Parallel_AddSqldan Parallel_Executeseperti yang dijelaskan dalam artikel ini oleh Alan Kaplan (SQL2005 + saja).
  • Tugas Windows Terjadwal : Terdaftar untuk kelengkapan, tapi saya bukan penggemar opsi ini.

Jika itu saya, saya mungkin akan menggunakan beberapa SQL Agent Jobs dalam skenario yang lebih sederhana, dan paket SSIS dalam skenario yang lebih kompleks.

Dalam kasus Anda, kecuali jika Anda mencoba meluncurkan 200 utas terpisah, beberapa pekerjaan Agen terjadwal terdengar seperti pilihan yang sederhana dan mudah dikelola.

Satu komentar terakhir : SQL sudah mencoba untuk memparalelkan operasi individual kapan saja *. Ini berarti menjalankan 2 tugas pada saat yang sama alih-alih setelah satu sama lain tidak ada jaminan bahwa itu akan selesai lebih cepat. Tes dengan hati-hati untuk melihat apakah itu benar-benar meningkatkan sesuatu atau tidak.

Kami memiliki pengembang yang membuat paket DTS untuk menjalankan 8 tugas secara bersamaan. Sayangnya, itu hanya server 4-CPU :)

* Dengan asumsi pengaturan default. Ini dapat dimodifikasi dengan mengubah Derajat Maksimal Paralelisme atau Masker Afinitas server, atau dengan menggunakan petunjuk kueri MAXDOP.


2

Taruhan terbaik Anda adalah menciptakan tiga pekerjaan terpisah dengan jadwal yang sama untuk memulai pekerjaan secara bersamaan. Bergantung pada apa yang dikerjakan, Anda harus berhati-hati memantau pemblokiran dan kebuntuan.

Pilihan lain adalah membuat paket SSIS dengan N jumlah operator untuk memanggil SP secara paralel


2

Anda bisa menggunakan Powershell. Dengan asumsi Anda bekerja dengan SQL Server, Anda dapat melakukan sesuatu seperti ini: (diuji dan dibersihkan sekarang)

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

Catatan: Saya mengambil ini dari sesuatu yang serupa yang saya lakukan di sini yang diuji: https://sqlstudies.com/2016/02/24/powershell-script-to-create-multiple-sql-server-connections/

Dalam yang saya menjalankan loop untuk membuat banyak perintah melakukan hal yang sama. Skrip ini menggunakan blok skrip untuk menjalankan setiap perintah secara serempak tetapi dengan perintah aktual yang berbeda. Untuk mempermudah, saya telah memasukkan daftar perintah yang ingin Anda jalankan ke dalam array dan loop melalui array.


1

Saya menggunakan aplikasi C # dengan multithread Parallel.ForEachuntuk memanggil sp dengan parameter yang berbeda. Memiliki tiga bagian. Init, Tubuh, lokal Akhirnya

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

Anda juga bisa menggunakannya ForEach -Paralleldi Powershell.

Contoh di bawah ini (diambil dari pertanyaan saya Powershell Run Stored Procedures in Parallel in Database ) akan menjalankan semua prosedur yang tersimpan dalam database:

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

Karena ini mengingatkan saya pada use case yang saya miliki di tempat kerja, saya akan menjelaskan bagaimana kita menyelesaikannya:

Pertama seperti yang sudah dikatakan, saya tidak berpikir ada Unix "nohup" -seperti ada di SQL: satu connexion = satu pernyataan, dengan semua yang berjalan (kunci, komit, kesalahan ...)

Kami menemukan cara kami menggunakan ETL Talend gratis, mengonfigurasinya untuk terhubung ke DB, dan menjalankan banyak pekerjaan paralel yang membungkus prosedur yang tersimpan.

Kami menggunakan Iteratekomponen dan loop sebanyak yang kami butuhkan, memungkinkan multi-threadsopsi.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.