Menggunakan Beberapa Set Hasil Aktif (MARS) di SQL Server Native Client

Berlaku untuk:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics AnalyticsPlatform System (PDW)

Penting

SQL Server Native Client (sering disingkat SNAC) telah dihapus dari SQL Server 2022 (16.x) dan SQL Server Management Studio 19 (SSMS). SQL Server Native Client (SQLNCLI atau SQLNCLI11) dan Penyedia Microsoft OLE DB warisan untuk SQL Server (SQLOLEDB) tidak direkomendasikan untuk pengembangan aplikasi baru. Beralih ke Microsoft OLE DB Driver (MSOLEDBSQL) baru untuk SQL Server atau Microsoft ODBC Driver terbaru untuk SQL Server ke depannya. Untuk SQLNCLI yang dikirim sebagai komponen SQL Server Database Engine (versi 2012 hingga 2019), lihat pengecualian Siklus Hidup Dukungan ini.

SQL Server 2005 (9.x) memperkenalkan dukungan untuk beberapa set hasil aktif (MARS) dalam aplikasi yang mengakses Mesin Database. Dalam versi SQL Server yang lebih lama, aplikasi database tidak dapat mempertahankan beberapa pernyataan aktif pada koneksi. Saat menggunakan kumpulan hasil default SQL Server, aplikasi harus memproses atau membatalkan semua tataan hasil dari satu batch sebelum dapat menjalankan batch lain pada koneksi tersebut. SQL Server 2005 (9.x) memperkenalkan atribut koneksi baru yang memungkinkan aplikasi memiliki lebih dari satu permintaan yang tertunda per koneksi, dan khususnya, memiliki lebih dari satu tataan hasil default aktif per koneksi.

MARS menyederhanakan desain aplikasi dengan kemampuan baru berikut:

  • Aplikasi dapat membuka beberapa kumpulan hasil default dan dapat menginterelasikan pembacaan darinya.

  • Aplikasi dapat menjalankan pernyataan lain (misalnya, INSERT, UPDATE, DELETE, dan panggilan prosedur tersimpan) saat tataan hasil default terbuka.

Aplikasi yang menggunakan MARS akan menemukan panduan berikut bermanfaat:

  • Kumpulan hasil default harus digunakan untuk kumpulan hasil berumur pendek atau pendek yang dihasilkan oleh pernyataan SQL tunggal (SELECT, DML dengan OUTPUT, RECEIVE, READ TEXT, dan sebagainya).

  • Kursor server harus digunakan untuk set hasil yang lebih lama atau besar yang dihasilkan oleh pernyataan SQL tunggal.

  • Selalu baca hingga akhir hasil untuk permintaan prosedural terlepas dari apakah mereka mengembalikan hasil atau tidak, dan untuk batch yang mengembalikan beberapa hasil.

  • Jika memungkinkan, gunakan panggilan API untuk mengubah properti koneksi dan mengelola transaksi sesuai dengan pernyataan Transact-SQL.

  • Di MARS, peniruan cakupan sesi dilarang saat batch bersamaan berjalan.

Catatan

Secara default, fungsionalitas MARS tidak diaktifkan oleh driver. Untuk menggunakan MARS saat menyambungkan ke SQL Server dengan SQL Server Native Client, Anda harus secara khusus mengaktifkan MARS dalam string koneksi. Namun, beberapa aplikasi dapat mengaktifkan MARS secara default, jika aplikasi mendeteksi bahwa driver mendukung MARS. Untuk aplikasi ini, Anda dapat menonaktifkan MARS dalam string koneksi sesuai kebutuhan. Untuk informasi selengkapnya, lihat bagian driver SQL Server Native Client OLE DB dan driver ODBC SQL Server Native Client, nanti dalam topik ini.

SQL Server Native Client tidak membatasi jumlah pernyataan aktif pada koneksi.

Aplikasi umum yang tidak perlu memiliki lebih dari satu batch multi-pernyataan atau prosedur tersimpan yang dijalankan pada saat yang sama akan mendapat manfaat dari MARS tanpa harus memahami bagaimana MARS diimplementasikan. Namun, aplikasi dengan persyaratan yang lebih kompleks memang perlu memperhitungkan hal ini.

MARS memungkinkan eksekusi interleaved dari beberapa permintaan dalam satu koneksi. Artinya, ini memungkinkan batch untuk berjalan, dan dalam eksekusinya, memungkinkan permintaan lain untuk dijalankan. Namun, perhatikan bahwa MARS didefinisikan dalam hal interleaving, bukan dalam hal eksekusi paralel.

Infrastruktur MARS memungkinkan beberapa batch untuk dieksekusi secara bergantian, meskipun eksekusi hanya dapat dialihkan pada titik yang ditentukan dengan baik. Selain itu, sebagian besar pernyataan harus berjalan secara atomik dalam batch. Pernyataan yang mengembalikan baris ke klien, yang kadang-kadang disebut sebagai titik hasil, diizinkan untuk menginterogasi eksekusi sebelum penyelesaian saat baris dikirim ke klien, misalnya:

  • SELECT

  • FETCH

  • TERIMA

Pernyataan lain yang dijalankan sebagai bagian dari prosedur tersimpan atau batch harus berjalan hingga selesai sebelum eksekusi dapat dialihkan ke permintaan MARS lainnya.

Cara yang tepat di mana batch eksekusi interleave dipengaruhi oleh sejumlah faktor, dan sulit untuk memprediksi urutan yang tepat di mana perintah dari beberapa batch yang berisi titik hasil akan dijalankan. Berhati-hatilah untuk menghindari efek samping yang tidak diinginkan karena eksekusi interleaved dari batch kompleks tersebut.

Hindari masalah dengan menggunakan panggilan API daripada pernyataan Transact-SQL untuk mengelola status koneksi (SET, USE) dan transaksi (BEGIN TRAN, COMMIT, ROLLBACK) dengan tidak menyertakan pernyataan ini dalam batch multi-pernyataan yang juga berisi titik hasil, dan dengan menserialisasikan eksekusi batch tersebut dengan mengonsumsi atau membatalkan semua hasil.

Catatan

Prosedur batch atau tersimpan yang memulai transaksi manual atau implisit ketika MARS diaktifkan harus menyelesaikan transaksi sebelum batch keluar. Jika tidak, SQL Server mengembalikan semua perubahan yang dilakukan oleh transaksi ketika batch selesai. Transaksi semacam itu dikelola oleh SQL Server sebagai transaksi cakupan batch. Ini adalah jenis transaksi baru yang diperkenalkan di SQL Server 2005 (9.x) untuk memungkinkan prosedur tersimpan yang berkinerja baik yang ada untuk digunakan ketika MARS diaktifkan. Untuk informasi selengkapnya tentang transaksi cakupan batch, lihat Pernyataan Transaksi (Transact-SQL).

Untuk contoh penggunaan MARS dari ADO, lihat Menggunakan ADO dengan SQL Server Native Client.

OLTP Dalam Memori

OLTP dalam memori mendukung MARS menggunakan kueri dan prosedur tersimpan yang dikompilasi secara asli. MARS memungkinkan permintaan data dari beberapa kueri tanpa perlu sepenuhnya mengambil setiap tataan hasil sebelum mengirim permintaan untuk mengambil baris dari kumpulan hasil baru. Agar berhasil membaca dari beberapa kumpulan hasil terbuka, Anda harus menggunakan koneksi yang diaktifkan MARS.

MARS dinonaktifkan secara default sehingga Anda harus mengaktifkannya secara eksplisit dengan menambahkan MultipleActiveResultSets=True ke string koneksi. Contoh berikut menunjukkan cara menyambungkan ke instans SQL Server dan menentukan bahwa MARS diaktifkan:

Data Source=MSSQL; Initial Catalog=AdventureWorks; Integrated Security=SSPI; MultipleActiveResultSets=True  

MARS dengan OLTP Dalam Memori pada dasarnya sama dengan MARS di sisa mesin SQL. Berikut ini mencantumkan perbedaan saat menggunakan MARS dalam tabel yang dioptimalkan memori dan prosedur tersimpan yang dikompilasi secara asli.

Tabel MARS dan memori yang dioptimalkan

Berikut ini adalah perbedaan antara tabel berbasis disk dan memori yang dioptimalkan saat menggunakan koneksi yang diaktifkan MARS:

  • Dua pernyataan dapat memodifikasi data dalam objek target yang sama tetapi jika keduanya mencoba mengubah rekaman yang sama, konflik tulis-tulis akan menyebabkan operasi baru gagal. Namun, jika kedua operasi memodifikasi rekaman yang berbeda, operasi akan berhasil.

  • Setiap pernyataan berjalan di bawah isolasi SNAPSHOT sehingga operasi baru tidak dapat melihat perubahan yang dibuat oleh pernyataan yang ada. Bahkan jika pernyataan bersamaan dijalankan di bawah transaksi yang sama, mesin SQL membuat transaksi cakupan batch untuk setiap pernyataan yang terisolasi satu sama lain. Namun, transaksi yang dicakup batch masih terikat bersama sehingga pembatalan satu transaksi cakupan batch memengaruhi transaksi lain dalam batch yang sama.

  • Operasi DDL tidak diizinkan dalam transaksi pengguna sehingga operasi tersebut akan segera gagal.

MARS dan prosedur tersimpan yang dikompilasi secara asli

Prosedur tersimpan yang dikompilasi secara asli dapat berjalan di koneksi yang diaktifkan MARS dan dapat menghasilkan eksekusi ke pernyataan lain hanya ketika titik hasil ditemui. Titik hasil memerlukan pernyataan SELECT, yang merupakan satu-satunya pernyataan dalam prosedur tersimpan yang dikompilasi secara asli yang dapat menghasilkan eksekusi ke pernyataan lain. Jika pernyataan SELECT tidak ada dalam prosedur yang tidak akan dihasilkannya, pernyataan tersebut akan berjalan hingga selesai sebelum pernyataan lain dimulai.

Transaksi MARS dan OLTP dalam memori

Perubahan yang dibuat oleh pernyataan dan blok atom yang saling berhubungan diisolasi satu sama lain. Misalnya, jika satu pernyataan atau blok atom membuat beberapa perubahan, dan kemudian menghasilkan eksekusi ke pernyataan lain, pernyataan baru tidak akan melihat perubahan yang dibuat oleh pernyataan pertama. Selain itu, ketika pernyataan pertama melanjutkan eksekusi, pernyataan tersebut tidak akan melihat perubahan apa pun yang dibuat oleh pernyataan lain. Pernyataan hanya akan melihat perubahan yang selesai dan diterapkan sebelum pernyataan dimulai.

Transaksi pengguna baru dapat dimulai dalam transaksi pengguna saat ini menggunakan pernyataan BEGIN TRANSACTION - ini hanya didukung dalam mode interop sehingga BEGIN TRANSACTION hanya dapat dipanggil dari pernyataan T-SQL, dan bukan dari dalam prosedur tersimpan yang dikompilasi secara asli. Anda dapat membuat titik penyimpanan dalam transaksi menggunakan SAVE TRANSACTION atau panggilan API ke transaksi. Simpan(save_point_name) untuk memutar kembali ke titik penyimpanan. Fitur ini juga hanya diaktifkan dari pernyataan T-SQL, dan bukan dari dalam prosedur tersimpan yang dikompilasi secara asli.

Indeks MARS dan penyimpan kolom

SQL Server (dimulai dengan 2016) mendukung MARS dengan indeks penyimpan kolom. SQL Server 2014 menggunakan MARS untuk koneksi baca-saja ke tabel dengan indeks penyimpan kolom. Namun, SQL Server 2014 tidak mendukung MARS untuk operasi bahasa manipulasi data bersamaan (DML) pada tabel dengan indeks penyimpan kolom. Ketika ini terjadi, SQL Server akan menghentikan koneksi dan membatalkan transaksi. SQL Server 2012 memiliki indeks penyimpan kolom baca-saja dan MARS tidak berlaku untuk mereka.

Penyedia OLE DB Klien Asli SQL Server

Penyedia SQL Server Native Client OLE DB mendukung MARS melalui penambahan properti inisialisasi sumber data SSPROP_INIT_MARSCONNECTION, yang diimplementasikan dalam kumpulan properti DBPROPSET_SQLSERVERDBINIT. Selain itu, kata kunci string koneksi baru, MarsConn, seperti yang telah ditambahkan. Ini menerima nilai benar atau salah ; false adalah default.

Properti sumber data DBPROP_MULTIPLECONNECTIONS default ke VARIANT_TRUE. Ini berarti penyedia akan menelurkan beberapa koneksi untuk mendukung beberapa perintah bersamaan dan objek set baris. Saat MARS diaktifkan, SQL Server Native Client dapat mendukung beberapa objek perintah dan set baris pada satu koneksi, sehingga MULTIPLE_CONNECTIONS diatur ke VARIANT_FALSE secara default.

Untuk informasi selengkapnya tentang penyempurnaan yang dilakukan pada kumpulan properti DBPROPSET_SQLSERVERDBINIT, lihat Properti Inisialisasi dan Otorisasi.

Contoh Penyedia OLE DB Klien Asli SQL Server

Dalam contoh ini, objek sumber data dibuat menggunakan penyedia SQL Server Native OLE DB, dan MARS diaktifkan menggunakan properti DBPROPSET_SQLSERVERDBINIT yang diatur sebelum objek sesi dibuat.

#include <sqlncli.h>  
  
IDBInitialize *pIDBInitialize = NULL;  
IDBCreateSession *pIDBCreateSession = NULL;  
IDBProperties *pIDBProperties = NULL;  
  
// Create the data source object.  
hr = CoCreateInstance(CLSID_SQLNCLI10, NULL,  
   CLSCTX_INPROC_SERVER,  
   IID_IDBInitialize,   
    (void**)&pIDBInitialize);  
  
hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void**)&pIDBProperties);  
  
// Set the MARS property.  
DBPROP rgPropMARS;  
  
// The following is necessary since MARS is off by default.  
rgPropMARS.dwPropertyID = SSPROP_INIT_MARSCONNECTION;  
rgPropMARS.dwOptions = DBPROPOPTIONS_REQUIRED;  
rgPropMARS.dwStatus = DBPROPSTATUS_OK;  
rgPropMARS.colid = DB_NULLID;  
V_VT(&(rgPropMARS.vValue)) = VT_BOOL;  
V_BOOL(&(rgPropMARS.vValue)) = VARIANT_TRUE;  
  
// Create the structure containing the properties.  
DBPROPSET PropSet;  
PropSet.rgProperties = &rgPropMARS;  
PropSet.cProperties = 1;  
PropSet.guidPropertySet = DBPROPSET_SQLSERVERDBINIT;  
  
// Get an IDBProperties pointer and set the initialization properties.  
pIDBProperties->SetProperties(1, &PropSet);  
pIDBProperties->Release();  
  
// Initialize the data source object.  
hr = pIDBInitialize->Initialize();  
  
//Create a session object from a data source object.  
IOpenRowset * pIOpenRowset = NULL;  
hr = IDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession));  
hr = pIDBCreateSession->CreateSession(  
   NULL,             // pUnkOuter  
   IID_IOpenRowset,  // riid  
  &pIOpenRowset ));  // ppSession  
  
// Create a rowset with a firehose mode cursor.  
IRowset *pIRowset = NULL;  
DBPROP rgRowsetProperties[2];  
  
// To get a firehose mode cursor request a   
// forward only read only rowset.  
rgRowsetProperties[0].dwPropertyID = DBPROP_IRowsetLocate;  
rgRowsetProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[0].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[0].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[0].vValue));  
rgRowsetProperties[0].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[0].vValue.boolVal = VARIANT_FALSE;  
  
rgRowsetProperties[1].dwPropertyID = DBPROP_IRowsetChange;  
rgRowsetProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[1].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[1].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[1].vValue));  
rgRowsetProperties[1].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[1].vValue.boolVal = VARIANT_FALSE;  
  
DBPROPSET rgRowsetPropSet[1];  
rgRowsetPropSet[0].rgProperties = rgRowsetProperties  
rgRowsetPropSet[0].cProperties = 2  
rgRowsetPropSet[0].guidPropertySet = DBPROPSET_ROWSET;  
  
hr = pIOpenRowset->OpenRowset (NULL,  
   &TableID,  
   NULL,  
   IID_IRowset,  
   1,  
   rgRowsetPropSet  
   (IUnknown**)&pIRowset);  

Driver ODBC Klien Asli SQL Server

Driver ODBC SQL Server Native Client mendukung MARS melalui penambahan ke fungsi SQLSetConnectAttr dan SQLGetConnectAttr . SQL_COPT_SS_MARS_ENABLED telah ditambahkan untuk menerima SQL_MARS_ENABLED_YES atau SQL_MARS_ENABLED_NO, dengan SQL_MARS_ENABLED_NO menjadi default. Selain itu, kata kunci string koneksi baru, Mars_Connection, seperti yang telah ditambahkan. Ini menerima nilai "ya" atau "tidak"; "tidak" adalah default.

Contoh Driver ODBC Klien Asli SQL Server

Dalam contoh ini, fungsi SQLSetConnectAttr digunakan untuk mengaktifkan MARS sebelum memanggil fungsi SQLDriverConnect untuk menyambungkan database. Setelah koneksi dibuat, dua fungsi SQLExecDirect dipanggil untuk membuat dua set hasil terpisah pada koneksi yang sama.

#include <sqlncli.h>  
  
SQLSetConnectAttr(hdbc, SQL_COPT_SS_MARS_ENABLED, SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER);  
SQLDriverConnect(hdbc, hwnd,   
   "DRIVER=SQL Server Native Client 10.0;  
   SERVER=(local);trusted_connection=yes;", SQL_NTS, szOutConn,   
   MAX_CONN_OUT, &cbOutConn, SQL_DRIVER_COMPLETE);  
  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1);  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2);  
  
// The 2nd execute would have failed with connection busy error if  
// MARS were not enabled.  
SQLExecDirect(hstmt1, L"SELECT * FROM Authors", SQL_NTS);  
SQLExecDirect(hstmt2, L"SELECT * FROM Titles", SQL_NTS);  
  
// Result set processing can interleave.  
SQLFetch(hstmt1);  
SQLFetch(hstmt2);  

Lihat Juga

Fitur Klien Asli SQL Server
Menggunakan Kumpulan Hasil Default SQL Server