Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği uygulama performansını geliştirmek için toplu işlem kullanma

Şunlar için geçerlidir:Azure SQL VeritabanıAzure SQL Yönetilen Örneği

Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği'ne yönelik toplu işlemler, uygulamalarınızın performansını ve ölçeklenebilirliğini önemli ölçüde artırır. Avantajları anlamak için bu makalenin ilk bölümü, sıralı ve toplu istekleri Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği'ndeki bir veritabanıyla karşılaştıran bazı örnek test sonuçlarını kapsar. Makalenin geri kalanında, Azure uygulamalarınızda toplu işlemi başarıyla kullanmanıza yardımcı olacak teknikler, senaryolar ve önemli noktalar gösterilir.

Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği için toplu işlem neden önemlidir?

Uzak hizmete yönelik çağrıları toplu olarak oluşturmak, performansı ve ölçeklenebilirliği artırmaya yönelik iyi bilinen bir stratejidir. Serileştirme, ağ aktarımı ve seri durumdan çıkarma gibi uzak bir hizmetle yapılan tüm etkileşimlerin sabit işleme maliyetleri vardır. Birçok ayrı işlemin tek bir toplu işlem halinde paketlenmesi bu maliyetleri en aza indirir.

Bu makalede, çeşitli toplu işleme stratejilerini ve senaryolarını incelemek istiyoruz. Bu stratejiler SQL Server kullanan şirket içi uygulamalar için de önemli olsa da, Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği için toplu işlem kullanımını vurgulamanın çeşitli nedenleri vardır:

  • Özellikle aynı Microsoft Azure veri merkezinin dışından Azure SQL Veritabanı'na veya Azure SQL Yönetilen Örneği'ne erişiyorsanız, Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği'ne erişimde büyük olasılıkla daha fazla ağ gecikme süresi vardır.
  • Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği'nin çok kiracılı özellikleri, veri erişim katmanının verimliliğinin veritabanının genel ölçeklenebilirliğiyle ilişkili olduğu anlamına gelir. Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği, önceden tanımlanmış kotaları aşan kullanıma yanıt olarak aktarım hızını azaltabilir veya azaltma özel durumlarıyla yanıt verebilir. Toplu işlem gibi verimlilikler, bu sınırlara ulaşmadan önce daha fazla iş yapmanıza olanak tanır.
  • Toplu işlem, birden çok veritabanı (parçalama) kullanan mimariler için de etkilidir. Her veritabanı birimiyle etkileşiminizin verimliliği, genel ölçeklenebilirliğinizde önemli bir faktördür.

Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği kullanmanın avantajlarından biri, veritabanını barındıran sunucuları yönetmeniz gerekmeyecek olmasıdır. Ancak bu yönetilen altyapı, veritabanı iyileştirmeleri hakkında farklı düşünmeniz gereken anlamına da gelir. Artık veritabanı donanımını veya ağ altyapısını geliştirmek için arama yapamayacaksınız. Microsoft Azure bu ortamları denetler. Denetleyebileceğiniz ana alan, uygulamanızın Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği ile nasıl etkileşimde bulunduğudur. Toplu işleme bu iyileştirmelerden biridir.

Bu makalenin ilk bölümünde, Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği kullanan .NET uygulamaları için çeşitli toplu iş teknikleri incelenmiştir. Son iki bölümde toplu işlem yönergeleri ve senaryolar ele alınıyor.

Toplu işlem stratejileri

Bu makaledeki zamanlama sonuçları hakkında not

Not

Sonuçlar kıyaslama değildir, ancak göreli performansı gösterme amaçlıdır. Zamanlamalar en az 10 test çalıştırmasının ortalamasına dayanır. İşlemler boş bir tabloya eklenir. Bu testler V12 öncesi olarak ölçülmüştür ve yeni DTU hizmet katmanlarını veya sanal çekirdek hizmet katmanlarını kullanarak V12 veritabanında karşılaşabileceğiniz aktarım hızına karşılık gelmez. Toplu işlem tekniğinin göreli avantajı benzer olmalıdır.

İşlemler

İşlemleri tartışarak toplu işlemlerin gözden geçirilmesine başlamak garip görünüyor. Ancak istemci tarafı işlemlerinin kullanımı, performansı geliştiren hafif bir sunucu tarafı toplu işlem etkisine sahiptir. İşlemler yalnızca birkaç kod satırıyla eklenebilir, bu nedenle sıralı işlemlerin performansını geliştirmek için hızlı bir yol sağlar.

Basit bir tablodaki ekleme ve güncelleştirme işlemlerinin bir dizisini içeren aşağıdaki C# kodunu göz önünde bulundurun.

List<string> dbOperations = new List<string>();
dbOperations.Add("update MyTable set mytext = 'updated text' where id = 1");
dbOperations.Add("update MyTable set mytext = 'updated text' where id = 2");
dbOperations.Add("update MyTable set mytext = 'updated text' where id = 3");
dbOperations.Add("insert MyTable values ('new value',1)");
dbOperations.Add("insert MyTable values ('new value',2)");
dbOperations.Add("insert MyTable values ('new value',3)");

Aşağıdaki ADO.NET kodu bu işlemleri sıralı olarak gerçekleştirir.

using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
{
    conn.Open();

    foreach(string commandString in dbOperations)
    {
        SqlCommand cmd = new SqlCommand(commandString, conn);
        cmd.ExecuteNonQuery();
    }
}

Bu kodu iyileştirmenin en iyi yolu, bu çağrıların istemci tarafı toplu işleminin bir biçimini uygulamaktır. Ancak, bir işlemdeki çağrı dizisini sarmalayarak bu kodun performansını artırmanın basit bir yolu vardır. Burada işlem kullanan kodun aynısı yer alır.

using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
{
    conn.Open();
    SqlTransaction transaction = conn.BeginTransaction();

    foreach (string commandString in dbOperations)
    {
        SqlCommand cmd = new SqlCommand(commandString, conn, transaction);
        cmd.ExecuteNonQuery();
    }

    transaction.Commit();
}

İşlemler aslında bu örneklerin her ikisinde de kullanılıyor. İlk örnekte her çağrı örtük bir işlemdir. İkinci örnekte, açık bir işlem tüm çağrıları sarmalar. Önceden yazma işlem günlüğünün belgelerine göre, işlem işlendiğinde günlük kayıtları diske boşaltılır. Bu nedenle, bir işleme daha fazla çağrı ekleyerek işlem günlüğüne yazma işlemi tamamlanana kadar geciktirebilir. Aslında, sunucunun işlem günlüğüne yazma işlemleri için toplu işlemi etkinleştirebilirsiniz.

Aşağıdaki tabloda bazı geçici test sonuçları gösterilmektedir. Testler aynı sıralı eklemeleri işlemlerle ve işlem olmadan gerçekleştirdi. Daha fazla bakış açısı için, ilk test kümesi bir dizüstü bilgisayardan Microsoft Azure'daki veritabanına uzaktan çalıştı. İkinci test kümesi, aynı Microsoft Azure veri merkezinde (Batı ABD) bulunan bir bulut hizmetinden ve veritabanından çalıştırıldı. Aşağıdaki tabloda, işlem içeren ve olmayan sıralı eklemelerin milisaniye cinsinden süresi gösterilmektedir.

Şirket içi ortamdan Azure'a:

Operasyonlar İşlem yok (ms) İşlem (ms)
1 130 402
10 1208 1226
100 12662 10395
1000 128852 102917

Azure'da Azure'a (aynı veri merkezi):

Operasyonlar İşlem yok (ms) İşlem (ms)
1 21 26
10 220 56
100 2145 341
1000 21479 2756

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

Önceki test sonuçlarına bağlı olarak, bir işlemdeki tek bir işlemi sarmalama aslında performansı düşürür. Ancak tek bir işlem içindeki işlem sayısını artırdıkça performans artışı daha belirgin hale gelir. Microsoft Azure veri merkezinde tüm işlemler gerçekleştiğinde performans farkı da daha belirgindir. Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği'ni Microsoft Azure veri merkezi dışından kullanmanın artan gecikme süresi, işlemleri kullanmanın performans kazancını gölgede tutar.

İşlemlerin kullanımı performansı artırabilir, ancak işlemler ve bağlantılar için en iyi yöntemleri gözlemlemeye devam edin. İşlemi olabildiğince kısa tutun ve iş tamamlandıktan sonra veritabanı bağlantısını kapatın. Önceki örnekteki using deyimi, sonraki kod bloğu tamamlandığında bağlantının kapatılmasını sağlar.

Önceki örnekte, iki satırlı herhangi bir ADO.NET koduna yerel bir işlem ekleyebileceğiniz gösterilmektedir. İşlemler, sıralı ekleme, güncelleştirme ve silme işlemleri yapan kodun performansını geliştirmek için hızlı bir yol sunar. Ancak en hızlı performans için, tablo değerli parametreler gibi istemci tarafı toplu işlemlerinden yararlanmak için kodu daha fazla değiştirmeyi göz önünde bulundurun.

ADO.NET'daki işlemler hakkında daha fazla bilgi için bkz . ADO.NET'de Yerel İşlemler.

Tablo değerli parametreler

Tablo değerli parametreler Transact-SQL deyimleri, saklı yordamlar ve işlevlerde parametre olarak kullanıcı tanımlı tablo türlerini destekler. Bu istemci tarafı toplu işlem tekniği, tablo değerli parametresi içinde birden çok veri satırı göndermenizi sağlar. Tablo değerli parametreleri kullanmak için önce bir tablo türü tanımlayın. Aşağıdaki Transact-SQL deyimi MyTableType adlı bir tablo türü oluşturur.

    CREATE TYPE MyTableType AS TABLE
    ( mytext TEXT,
      num INT );

Kodda, tablo türünün tam olarak aynı ad ve türlerine sahip bir DataTable oluşturursunuz. Bu DataTable'ı bir metin sorgusundaki veya saklı yordam çağrısındaki bir parametreye geçirin. Aşağıdaki örnekte bu teknik gösterilmektedir:

using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
{
    connection.Open();

    DataTable table = new DataTable();
    // Add columns and rows. The following is a simple example.
    table.Columns.Add("mytext", typeof(string));
    table.Columns.Add("num", typeof(int));
    for (var i = 0; i < 10; i++)
    {
        table.Rows.Add(DateTime.Now.ToString(), DateTime.Now.Millisecond);
    }

    SqlCommand cmd = new SqlCommand(
        "INSERT INTO MyTable(mytext, num) SELECT mytext, num FROM @TestTvp",
        connection);

    cmd.Parameters.Add(
        new SqlParameter()
        {
            ParameterName = "@TestTvp",
            SqlDbType = SqlDbType.Structured,
            TypeName = "MyTableType",
            Value = table,
        });

    cmd.ExecuteNonQuery();
}

Önceki örnekte, SqlCommand nesnesi tablo değerli bir parametreden @TestTvp satırlar ekler. Daha önce oluşturulan DataTable nesnesi, SqlCommand.Parameters.Add yöntemiyle bu parametreye atanır. Eklemelerin tek bir çağrıda toplu olarak çalıştırılması, sıralı eklemelere göre performansı önemli ölçüde artırır.

Önceki örneği daha da geliştirmek için metin tabanlı komut yerine saklı yordam kullanın. Aşağıdaki Transact-SQL komutu SimpleTestTableType tablo değerli parametresini alan bir saklı yordam oluşturur.

CREATE PROCEDURE [dbo].[sp_InsertRows]
@TestTvp as MyTableType READONLY
AS
BEGIN
INSERT INTO MyTable(mytext, num)
SELECT mytext, num FROM @TestTvp
END
GO

Ardından önceki kod örneğindeki SqlCommand nesne bildirimini aşağıdakiyle değiştirin.

SqlCommand cmd = new SqlCommand("sp_InsertRows", connection);
cmd.CommandType = CommandType.StoredProcedure;

Çoğu durumda, tablo değerli parametreler diğer toplu işleme tekniklerine göre eşdeğer veya daha iyi performansa sahiptir. Tablo değerli parametreler genellikle tercih edilir çünkü bunlar diğer seçeneklere göre daha esnektir. Örneğin, SQL toplu kopyalama gibi diğer teknikler yalnızca yeni satırların eklenmesine izin verir. Ancak tablo değerli parametrelerle saklı yordamdaki mantığı kullanarak hangi satırların güncelleştirme ve hangilerinin ekleme olduğunu belirleyebilirsiniz. Tablo türü, belirtilen satırın eklenmesi, güncelleştirilmesi veya silinmesi gerektiğini belirten bir "İşlem" sütunu içerecek şekilde de değiştirilebilir.

Aşağıdaki tabloda, tablo değerli parametrelerin milisaniye cinsinden kullanımına yönelik geçici test sonuçları gösterilmektedir.

Operasyonlar Şirket içinde Azure'a (ms) Azure aynı veri merkezi (ms)
1 124 32
10 131 25
100 338 51
1000 2615 382
10000 23830 3586

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

Toplu işlemden elde edilir performans kazancı hemen görünür. Önceki sıralı testte 1000 işlem veri merkezinin dışında 129 saniye ve veri merkezinin içinden 21 saniye sürmüştü. Ancak tablo değerli parametrelerle 1000 işlem veri merkezinin dışında yalnızca 2,6 saniye ve veri merkezi içinde 0,4 saniye sürer.

Tablo değerli parametreler hakkında daha fazla bilgi için bkz . Tablo Değerli Parametreler.

SQL toplu kopyalama

SQL toplu kopyalama, hedef veritabanına büyük miktarda veri eklemenin başka bir yoludur. .NET uygulamaları toplu ekleme işlemleri gerçekleştirmek için SqlBulkCopy sınıfını kullanabilir. SqlBulkCopy işlevinde komut satırı aracı, Bcp.exe veya Transact-SQL deyimi BULK INSERT ile benzerdir. Aşağıdaki kod örneği, kaynak DataTable tablosundaki satırların hedef tablo olan MyTable'a toplu olarak nasıl kopyalanmasını gösterir.

using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
{
    connection.Open();

    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "MyTable";
        bulkCopy.ColumnMappings.Add("mytext", "mytext");
        bulkCopy.ColumnMappings.Add("num", "num");
        bulkCopy.WriteToServer(table);
    }
}

Tablo değerli parametreler yerine toplu kopyalamanın tercih edildiği bazı durumlar vardır. Tablo Değerli Parametreler makalesindeki Tablo Değerli parametreleri ile BULK INSERT işlemlerini karşılaştırma tablosuna bakın.

Aşağıdaki geçici test sonuçları, SqlBulkCopy ile toplu işleme performansını milisaniye cinsinden gösterir.

Operasyonlar Şirket içinde Azure'a (ms) Azure aynı veri merkezi (ms)
1 433 57
10 441 32
100 636 53
1000 2535 341
10000 21605 2737

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

Daha küçük toplu iş boyutlarında tablo değerli parametrelerin kullanılması SqlBulkCopy sınıfından daha iyi performans gösterir. Ancak SqlBulkCopy, 1.000 ve 10.000 satırlık testler için tablo değerli parametrelerden %12-31 daha hızlı performans gösterdi. Tablo değerli parametreler gibi SqlBulkCopy de toplu eklemeler için iyi bir seçenektir, özellikle de toplu işlenmemiş işlemlerin performansıyla karşılaştırıldığında.

ADO.NET toplu kopyalama hakkında daha fazla bilgi için bkz . Toplu Kopyalama İşlemleri.

Çok satırlı parametreli INSERT deyimleri

Küçük toplu işlemler için bir alternatif, birden çok satır ekleyen büyük bir parametreli INSERT deyimi oluşturmaktır. Aşağıdaki kod örneği bu tekniği gösterir.

using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
{
    connection.Open();

    string insertCommand = "INSERT INTO [MyTable] ( mytext, num ) " +
        "VALUES (@p1, @p2), (@p3, @p4), (@p5, @p6), (@p7, @p8), (@p9, @p10)";

    SqlCommand cmd = new SqlCommand(insertCommand, connection);

    for (int i = 1; i <= 10; i += 2)
    {
        cmd.Parameters.Add(new SqlParameter("@p" + i.ToString(), "test"));
        cmd.Parameters.Add(new SqlParameter("@p" + (i+1).ToString(), i));
    }

    cmd.ExecuteNonQuery();
}

Bu örnek temel kavramı göstermeye yöneliktir. Daha gerçekçi bir senaryo, sorgu dizesini ve komut parametrelerini aynı anda oluşturmak için gerekli varlıklar arasında döngü yapar. Toplam 2100 sorgu parametresiyle sınırlısınız, bu nedenle bu şekilde işlenebilen toplam satır sayısını sınırlar.

Aşağıdaki geçici test sonuçları, bu tür bir insert deyiminin performansını milisaniye cinsinden gösterir.

Operasyonlar Tablo değerli parametreler (ms) Tek deyimli INSERT (ms)
1 32 20
10 30 25
100 33 51

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

Bu yaklaşım, 100 satırdan az olan toplu işlemler için biraz daha hızlı olabilir. İyileştirme küçük olsa da bu teknik, uygulama senaryonuzda iyi çalışabilecek başka bir seçenektir.

Dataadapter

DataAdapter sınıfı bir DataSet nesnesini değiştirmenize ve sonra değişiklikleri INSERT, UPDATE ve DELETE işlemleri olarak göndermenize olanak tanır. DataAdapter'ı bu şekilde kullanıyorsanız, her ayrı işlem için ayrı çağrılar yapıldığını unutmayın. Performansı geliştirmek için UpdateBatchSize özelliğini bir kerede toplu işlenecek işlem sayısı olarak kullanın. Daha fazla bilgi için bkz . DataAdapters Kullanarak Toplu İşlem Gerçekleştirme.

Varlık Çerçevesi

Entity Framework Core toplu işlemi destekler.

XML

Tamlık için XML'i toplu iş stratejisi olarak konuşmanın önemli olduğunu hissediyoruz. Bununla birlikte, XML kullanımının diğer yöntemlere ve çeşitli dezavantajlara göre hiçbir avantajı yoktur. Yaklaşım tablo değerli parametrelere benzer, ancak kullanıcı tanımlı tablo yerine bir XML dosyası veya dizesi saklı yordama geçirilir. saklı yordam saklı yordamdaki komutları ayrıştırıyor.

Bu yaklaşımın çeşitli dezavantajları vardır:

  • XML ile çalışmak hantal ve hataya eğilimli olabilir.
  • Veritabanında XML ayrıştırma cpu yoğunluklu olabilir.
  • Çoğu durumda, bu yöntem tablo değerli parametrelerden daha yavaştır.

Bu nedenlerden dolayı, toplu sorgular için XML kullanılması önerilmez.

Toplu işlemde dikkat edilmesi gerekenler

Aşağıdaki bölümler, Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği uygulamalarında toplu işlem kullanımına yönelik daha fazla kılavuz sağlar.

Avantajlar ve Dezavantajlar

Mimarinize bağlı olarak, toplu işlem performans ve dayanıklılık arasında bir denge içerebilir. Örneğin, rolünüzün beklenmedik bir şekilde devre dışı bırakıldığı senaryoyu düşünün. Bir veri satırını kaybederseniz, etki büyük bir toplu yayımlanmamış satırları kaybetmenin etkisinden daha küçük olur. Satırları belirli bir zaman penceresinde veritabanına göndermeden önce arabelleğe aldığınızda daha büyük bir risk vardır.

Bu denge nedeniyle, toplu olarak yaptığınız işlemlerin türünü değerlendirin. Daha az kritik verilerle daha agresif bir şekilde toplu iş yapın (daha büyük toplu işlemler ve daha uzun zaman pencereleri).

Toplu iş boyutu

Testlerimizde genellikle büyük toplu işleri daha küçük parçalara ayırmanın bir avantajı yoktu. Aslında, bu alt bölüm genellikle tek bir büyük toplu iş göndermekten daha yavaş performansa neden oldu. Örneğin, 1000 satır eklemek istediğiniz bir senaryo düşünün. Aşağıdaki tabloda, tablo değerli parametreleri kullanarak daha küçük toplu işlere bölündüğünde 1000 satır eklenmesinin ne kadar sürdüğü gösterilmektedir.

Toplu iş boyutu Yinelemeler Tablo değerli parametreler (ms)
1000 1 347
500 2 355
100 10 465
50 20 630

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

1000 satır için en iyi performansın tümünü aynı anda göndermek olduğunu görebilirsiniz. Diğer testlerde (burada gösterilmiyor), 10000 satırlık bir toplu işi 5000'lik iki toplu işe bölmek için küçük bir performans kazancı elde edildi. Ancak bu testlerin tablo şeması nispeten basittir, bu nedenle bu bulguları doğrulamak için belirli verilerinizde ve toplu iş boyutlarınızda testler yapmanız gerekir.

Dikkate alınması gereken bir diğer faktör de, toplam toplu iş çok büyük olursa Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği'nin toplu işlemi azaltması ve işlemeyi reddetmesidir. En iyi sonuçları elde etmek için, ideal bir toplu iş boyutu olup olmadığını belirlemek için senaryonuzu test edin. Performansa veya hatalara göre hızlı ayarlamaları etkinleştirmek için toplu iş boyutunu çalışma zamanında yapılandırılabilir hale getirin.

Son olarak, toplu iş boyutunu toplu işlemle ilişkili risklerle dengeleyin. Geçici hatalar varsa veya rol başarısız olursa, işlemi yeniden denemenin veya toplu işteki verileri kaybetmenin sonuçlarını göz önünde bulundurun.

Paralel işleme

Toplu iş boyutunu küçültme yaklaşımını benimsediyseniz ancak işi yürütmek için birden çok iş parçacığı kullandıysanız ne olur? Yine testlerimiz, birkaç küçük çok iş parçacıklı toplu işlemin genellikle tek bir büyük toplu işlemden daha kötü performans gösterdiğini gösterdi. Aşağıdaki test, bir veya daha fazla paralel toplu işe 1000 satır eklemeyi dener. Bu test, daha fazla eşzamanlı toplu işlemin performansı ne kadar azaltmış olduğunu gösterir.

Toplu iş boyutu [Yinelemeler] İki iş parçacığı (ms) Dört iş parçacığı (ms) Altı iş parçacığı (ms)
1000 [1] 277 315 266
500 [2] 548 278 Kategori 256
250 [4] 405 329 265
100 [10] 488 439 391

Not

Sonuçlar karşılaştırma değildir. Bu makaledeki zamanlama sonuçlarıyla ilgili nota bakın.

Paralellik nedeniyle performans düşüşü için çeşitli olası nedenler vardır:

  • Bir yerine birden çok eşzamanlı ağ çağrısı vardır.
  • Tek bir tabloya yönelik birden çok işlem çekişme ve engellemeye neden olabilir.
  • Çoklu iş parçacığı kullanımıyla ilişkili ek yükleri vardır.
  • Birden çok bağlantı açmanın maliyeti, paralel işlemenin avantajından daha ağır basıyor.

Farklı tabloları veya veritabanlarını hedeflerseniz, bu stratejiyle bazı performans kazançları görmek mümkündür. Veritabanı parçalama veya federasyonlar bu yaklaşım için bir senaryo olabilir. Parçalama birden çok veritabanı kullanır ve her veritabanına farklı veriler yönlendirir. Her küçük toplu iş farklı bir veritabanına gidiyorsa, işlemleri paralel olarak gerçekleştirmek daha verimli olabilir. Ancak performans kazancı, çözümünüzde veritabanı parçalama kullanma kararının temeli olarak kullanılacak kadar önemli değildir.

Bazı tasarımlarda, daha küçük toplu işlemlerin paralel yürütülmesi, yük altındaki bir sistemde isteklerin aktarım hızının artmasına neden olabilir. Bu durumda, tek bir daha büyük toplu işlemi işlemek daha hızlı olsa da, birden çok toplu işlemi paralel olarak işlemek daha verimli olabilir.

Paralel yürütme kullanıyorsanız, en fazla çalışan iş parçacığı sayısını denetlemeyi göz önünde bulundurun. Daha küçük bir sayı daha az çekişmeye ve daha hızlı yürütme süresine neden olabilir. Ayrıca, bunun hem bağlantılarda hem de işlemlerde hedef veritabanına yerleştirmiş olduğu ek yükü de göz önünde bulundurun.

Veritabanı performansıyla ilgili tipik yönergeler toplu işlemleri de etkiler. Örneğin, büyük bir birincil anahtara veya birçok kümelenmemiş dizine sahip tablolar için ekleme performansı azalır.

Tablo değerli parametreler saklı yordam kullanıyorsa, yordamın başındaKI SET NOCOUNT ON komutunu kullanabilirsiniz. Bu deyim, yordamdaki etkilenen satırların sayısının döndürülmesi gizlenir. Ancak testlerimizde, SET NOCOUNT ON kullanımının herhangi bir etkisi olmadı veya performansı azalttı. Test saklı yordamı, tablo değerli parametresinden tek bir INSERT komutuyla basitti. Daha karmaşık saklı yordamların bu deyimden yararlanması mümkündür. Ancak saklı yordamınıza SET NOCOUNT ON eklenmesinin performansı otomatik olarak artırdığını varsaymayın. Etkisini anlamak için SET NOCOUNT ON deyimiyle ve olmadan saklı yordamınızı test edin.

Toplu işlem senaryoları

Aşağıdaki bölümlerde üç uygulama senaryosunda tablo değerli parametrelerin nasıl kullanılacağı açıklanmaktadır. İlk senaryoda arabelleğe alma ve toplu işlem işlemlerinin birlikte nasıl çalışabileceği gösterilmektedir. İkinci senaryo, tek bir saklı yordam çağrısında ana ayrıntı işlemleri gerçekleştirerek performansı artırır. Son senaryoda bir "UPSERT" işleminde tablo değerli parametrelerin nasıl kullanılacağı gösterilmektedir.

Tamponlama

Toplu işleme için açıkça aday olan bazı senaryolar olsa da, gecikmeli işleme ile toplu işlemden yararlanabilecek birçok senaryo vardır. Ancak gecikmeli işleme, beklenmeyen bir hata durumunda verilerin kaybolmasına da daha fazla risk taşır. Bu riski anlamak ve sonuçlarını göz önünde bulundurmak önemlidir.

Örneğin, her kullanıcının gezinti geçmişini izleyen bir web uygulaması düşünün. Uygulama, her sayfa isteğinde kullanıcının sayfa görünümünü kaydetmek için bir veritabanı çağrısı yapabilir. Ancak kullanıcıların gezinti etkinlikleri arabelleğe alınıp bu verileri toplu olarak veritabanına göndererek daha yüksek performans ve ölçeklenebilirlik elde edilebilir. Veritabanı güncelleştirmesini geçen süreye ve/veya arabellek boyutuna göre tetikleyebilirsiniz. Örneğin, bir kural toplu işlemin 20 saniye sonra veya arabellek 1000 öğeye ulaştığında işlenmesi gerektiğini belirtebilir.

Aşağıdaki kod örneği, bir izleme sınıfı tarafından tetiklenen arabelleğe alınan olayları işlemek için Reaktif Uzantılar - Rx kullanır. Arabellek dolduğunda veya zaman aşımına ulaşıldığında, kullanıcı verileri toplu işlemi tablo değerli bir parametreyle veritabanına gönderilir.

Aşağıdaki NavHistoryData sınıfı, kullanıcı gezinti ayrıntılarını modeller. Kullanıcı tanımlayıcısı, erişilen URL ve erişim süresi gibi temel bilgileri içerir.

public class NavHistoryData
{
    public NavHistoryData(int userId, string url, DateTime accessTime)
    { UserId = userId; URL = url; AccessTime = accessTime; }
    public int UserId { get; set; }
    public string URL { get; set; }
    public DateTime AccessTime { get; set; }
}

NavHistoryDataMonitor sınıfı, kullanıcı gezinti verilerini veritabanına arabelleğe almaktan sorumludur. Bir OnAdded olayı oluşturarak yanıt veren RecordUserNavigationEntry yöntemini içerir. Aşağıdaki kod, olayı temel alan gözlemlenebilir bir koleksiyon oluşturmak için Rx kullanan oluşturucu mantığını gösterir. Ardından Buffer yöntemiyle bu gözlemlenebilir koleksiyona abone olur. Aşırı yükleme, arabelleğin 20 saniyede bir veya 1000 girdide bir gönderilmesi gerektiğini belirtir.

public NavHistoryDataMonitor()
{
    var observableData =
        Observable.FromEventPattern<NavHistoryDataEventArgs>(this, "OnAdded");

    observableData.Buffer(TimeSpan.FromSeconds(20), 1000).Subscribe(Handler);
}

İşleyici, arabelleğe alınan tüm öğeleri tablo değerli bir türe dönüştürür ve ardından bu türü toplu işlemi işleyen saklı bir yordama geçirir. Aşağıdaki kod hem NavHistoryDataEventArgs hem de NavHistoryDataMonitor sınıfları için tam tanımı gösterir.

public class NavHistoryDataEventArgs : System.EventArgs
{
    public NavHistoryDataEventArgs(NavHistoryData data) { Data = data; }
    public NavHistoryData Data { get; set; }
}

public class NavHistoryDataMonitor
{
    public event EventHandler<NavHistoryDataEventArgs> OnAdded;

    public NavHistoryDataMonitor()
    {
        var observableData =
            Observable.FromEventPattern<NavHistoryDataEventArgs>(this, "OnAdded");

        observableData.Buffer(TimeSpan.FromSeconds(20), 1000).Subscribe(Handler);
    }

İşleyici, arabelleğe alınan tüm öğeleri tablo değerli bir türe dönüştürür ve ardından bu türü toplu işlemi işleyen saklı bir yordama geçirir. Aşağıdaki kod hem NavHistoryDataEventArgs hem de NavHistoryDataMonitor sınıfları için tam tanımı gösterir.

    public class NavHistoryDataEventArgs : System.EventArgs
    {
        if (OnAdded != null)
            OnAdded(this, new NavHistoryDataEventArgs(data));
    }

    protected void Handler(IList<EventPattern<NavHistoryDataEventArgs>> items)
    {
        DataTable navHistoryBatch = new DataTable("NavigationHistoryBatch");
        navHistoryBatch.Columns.Add("UserId", typeof(int));
        navHistoryBatch.Columns.Add("URL", typeof(string));
        navHistoryBatch.Columns.Add("AccessTime", typeof(DateTime));
        foreach (EventPattern<NavHistoryDataEventArgs> item in items)
        {
            NavHistoryData data = item.EventArgs.Data;
            navHistoryBatch.Rows.Add(data.UserId, data.URL, data.AccessTime);
        }

        using (SqlConnection connection = new SqlConnection(CloudConfigurationManager.GetSetting("Sql.ConnectionString")))
        {
            connection.Open();

            SqlCommand cmd = new SqlCommand("sp_RecordUserNavigation", connection);
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(
                new SqlParameter()
                {
                    ParameterName = "@NavHistoryBatch",
                    SqlDbType = SqlDbType.Structured,
                    TypeName = "NavigationHistoryTableType",
                    Value = navHistoryBatch,
                });

            cmd.ExecuteNonQuery();
        }
    }
}

Bu arabelleğe alma sınıfını kullanmak için uygulama statik bir NavHistoryDataMonitor nesnesi oluşturur. Kullanıcı bir sayfaya her eriştiğinde, uygulama NavHistoryDataMonitor.RecordUserNavigationEntry yöntemini çağırır. Arabelleğe alma mantığı, bu girdileri toplu olarak veritabanına göndermeye devam eder.

Ana ayrıntı

Tablo değerli parametreler basit INSERT senaryoları için kullanışlıdır. Ancak, birden fazla tablo içeren toplu eklemeler daha zor olabilir. "Ana/ayrıntı" senaryosu iyi bir örnektir. Ana tablo birincil varlığı tanımlar. Bir veya daha fazla ayrıntı tablosu varlık hakkında daha fazla veri depolar. Bu senaryoda, yabancı anahtar ilişkileri benzersiz bir ana varlıkla ayrıntıların ilişkisini zorunlu kılar. PurchaseOrder tablosunun ve ilişkili OrderDetail tablosunun basitleştirilmiş bir sürümünü düşünün. Aşağıdaki Transact-SQL dört sütunlu PurchaseOrder tablosunu oluşturur: OrderID, OrderDate, CustomerID ve Status.

CREATE TABLE [dbo].[PurchaseOrder](
[OrderID] [int] IDENTITY(1,1) NOT NULL,
[OrderDate] [datetime] NOT NULL,
[CustomerID] [int] NOT NULL,
[Status] [nvarchar](50) NOT NULL,
CONSTRAINT [PrimaryKey_PurchaseOrder]
PRIMARY KEY CLUSTERED ( [OrderID] ASC ))

Her sipariş bir veya daha fazla ürün satın alma işlemi içerir. Bu bilgiler PurchaseOrderDetail tablosunda yakalanır. Aşağıdaki Transact-SQL beş sütunlu PurchaseOrderDetail tablosunu oluşturur: OrderID, OrderDetailID, ProductID, UnitPrice ve OrderQty.

CREATE TABLE [dbo].[PurchaseOrderDetail](
[OrderID] [int] NOT NULL,
[OrderDetailID] [int] IDENTITY(1,1) NOT NULL,
[ProductID] [int] NOT NULL,
[UnitPrice] [money] NULL,
[OrderQty] [smallint] NULL,
CONSTRAINT [PrimaryKey_PurchaseOrderDetail] PRIMARY KEY CLUSTERED
( [OrderID] ASC, [OrderDetailID] ASC ))

PurchaseOrderDetail tablosundaki OrderID sütunu, PurchaseOrder tablosundaki bir siparişe başvurmalıdır. Yabancı anahtarın aşağıdaki tanımı bu kısıtlamayı zorlar.

ALTER TABLE [dbo].[PurchaseOrderDetail]  WITH CHECK ADD
CONSTRAINT [FK_OrderID_PurchaseOrder] FOREIGN KEY([OrderID])
REFERENCES [dbo].[PurchaseOrder] ([OrderID])

Tablo değerli parametreleri kullanmak için, her hedef tablo için bir kullanıcı tanımlı tablo türüne sahip olmanız gerekir.

CREATE TYPE PurchaseOrderTableType AS TABLE
( OrderID INT,
    OrderDate DATETIME,
    CustomerID INT,
    Status NVARCHAR(50) );
GO

CREATE TYPE PurchaseOrderDetailTableType AS TABLE
( OrderID INT,
    ProductID INT,
    UnitPrice MONEY,
    OrderQty SMALLINT );
GO

Ardından bu tür tabloları kabul eden bir saklı yordam tanımlayın. Bu yordam, bir uygulamanın tek bir çağrıda bir dizi sipariş ve sipariş ayrıntısını yerel olarak toplu işlemesine olanak tanır. Aşağıdaki Transact-SQL, bu satın alma siparişi örneği için tam saklı yordam bildirimini sağlar.

CREATE PROCEDURE sp_InsertOrdersBatch (
@orders as PurchaseOrderTableType READONLY,
@details as PurchaseOrderDetailTableType READONLY )
AS
SET NOCOUNT ON;

-- Table that connects the order identifiers in the @orders
-- table with the actual order identifiers in the PurchaseOrder table
DECLARE @IdentityLink AS TABLE (
SubmittedKey int,
ActualKey int,
RowNumber int identity(1,1)
);

-- Add new orders to the PurchaseOrder table, storing the actual
-- order identifiers in the @IdentityLink table
INSERT INTO PurchaseOrder ([OrderDate], [CustomerID], [Status])
OUTPUT inserted.OrderID INTO @IdentityLink (ActualKey)
SELECT [OrderDate], [CustomerID], [Status] FROM @orders ORDER BY OrderID;

-- Match the passed-in order identifiers with the actual identifiers
-- and complete the @IdentityLink table for use with inserting the details
WITH OrderedRows As (
SELECT OrderID, ROW_NUMBER () OVER (ORDER BY OrderID) As RowNumber
FROM @orders
)
UPDATE @IdentityLink SET SubmittedKey = M.OrderID
FROM @IdentityLink L JOIN OrderedRows M ON L.RowNumber = M.RowNumber;

-- Insert the order details into the PurchaseOrderDetail table,
-- using the actual order identifiers of the master table, PurchaseOrder
INSERT INTO PurchaseOrderDetail (
[OrderID],
[ProductID],
[UnitPrice],
[OrderQty] )
SELECT L.ActualKey, D.ProductID, D.UnitPrice, D.OrderQty
FROM @details D
JOIN @IdentityLink L ON L.SubmittedKey = D.OrderID;
GO

Bu örnekte, yerel olarak tanımlanan @IdentityLink tablo yeni eklenen satırlardaki gerçek OrderID değerlerini depolar. Bu sipariş tanımlayıcıları ve @details tablo değerli parametrelerdeki @orders geçici OrderID değerlerinden farklıdır. Bu nedenle, @IdentityLink tablo daha sonra parametredeki @orders OrderID değerlerini PurchaseOrder tablosundaki yeni satırlar için gerçek OrderID değerlerine bağlar. Bu adımdan @IdentityLink sonra tablo, sipariş ayrıntılarının yabancı anahtar kısıtlamasını karşılayan gerçek OrderID değeriyle eklenmesini kolaylaştırabilir.

Bu saklı yordam koddan veya diğer Transact-SQL çağrılarından kullanılabilir. Kod örneği için bu makalenin tablo değerli parametreler bölümüne bakın. Aşağıdaki Transact-SQL, sp_InsertOrdersBatch nasıl çağıracaklarını gösterir.

declare @orders as PurchaseOrderTableType
declare @details as PurchaseOrderDetailTableType

INSERT @orders
([OrderID], [OrderDate], [CustomerID], [Status])
VALUES(1, '1/1/2013', 1125, 'Complete'),
(2, '1/13/2013', 348, 'Processing'),
(3, '1/12/2013', 2504, 'Shipped')

INSERT @details
([OrderID], [ProductID], [UnitPrice], [OrderQty])
VALUES(1, 10, $11.50, 1),
(1, 12, $1.58, 1),
(2, 23, $2.57, 2),
(3, 4, $10.00, 1)

exec sp_InsertOrdersBatch @orders, @details

Bu çözüm, her toplu işlemin 1'de başlayan bir OrderID değerleri kümesi kullanmasına olanak tanır. Bu geçici OrderID değerleri toplu iş ilişkilerini açıklar, ancak gerçek OrderID değerleri ekleme işlemi sırasında belirlenir. Önceki örnekte aynı deyimleri tekrar tekrar çalıştırabilir ve veritabanında benzersiz siparişler oluşturabilirsiniz. Bu nedenle, bu toplu işlem tekniğini kullanırken yinelenen siparişleri engelleyen daha fazla kod veya veritabanı mantığı eklemeyi göz önünde bulundurun.

Bu örnek, ana ayrıntı işlemleri gibi daha da karmaşık veritabanı işlemlerinin tablo değerli parametreler kullanılarak toplu işlenebileceğini gösterir.

UPSERT

Başka bir toplu işlem senaryosu, var olan satırları aynı anda güncelleştirmeyi ve yeni satır eklemeyi içerir. Bu işlem bazen "UPSERT" (güncelleştirme + ekleme) işlemi olarak adlandırılır. INSERT ve UPDATE için ayrı çağrılar yapmak yerine MERGE deyimi uygun bir değişiklik olabilir. MERGE deyimi tek bir çağrıda hem ekleme hem de güncelleştirme işlemlerini gerçekleştirebilir. MERGE deyimi kilitleme mekaniği ayrı INSERT ve UPDATE deyimlerinden farklı çalışır. Üretime dağıtmadan önce belirli iş yüklerinizi test edin.

Tablo değerli parametreler, güncelleştirmeleri ve eklemeleri gerçekleştirmek için MERGE deyimiyle birlikte kullanılabilir. Örneğin, şu sütunları içeren basitleştirilmiş bir Çalışan tablosu düşünün: EmployeeID, FirstName, LastName, SocialSecurityNumber:

CREATE TABLE [dbo].[Employee](
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[SocialSecurityNumber] [nvarchar](50) NOT NULL,
CONSTRAINT [PrimaryKey_Employee] PRIMARY KEY CLUSTERED
([EmployeeID] ASC ))

Bu örnekte, SocialSecurityNumber değerinin birden çok çalışanın BIRLEŞTİrme işlemini gerçekleştirmek için benzersiz olduğu gerçeğini kullanabilirsiniz. İlk olarak, kullanıcı tanımlı tablo türünü oluşturun:

CREATE TYPE EmployeeTableType AS TABLE
( Employee_ID INT,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    SocialSecurityNumber NVARCHAR(50) );
GO

Ardından, güncelleştirmeyi gerçekleştirmek ve eklemek için MERGE deyimini kullanan bir saklı yordam oluşturun veya kod yazın. Aşağıdaki örnek, EmployeeTableType türünde tablo değerli bir parametrede @employeesMERGE deyimini kullanır. Tablonun içeriği @employees burada gösterilmez.

MERGE Employee AS target
USING (SELECT [FirstName], [LastName], [SocialSecurityNumber] FROM @employees)
AS source ([FirstName], [LastName], [SocialSecurityNumber])
ON (target.[SocialSecurityNumber] = source.[SocialSecurityNumber])
WHEN MATCHED THEN
UPDATE SET
target.FirstName = source.FirstName,
target.LastName = source.LastName
WHEN NOT MATCHED THEN
    INSERT ([FirstName], [LastName], [SocialSecurityNumber])
    VALUES (source.[FirstName], source.[LastName], source.[SocialSecurityNumber]);

Daha fazla bilgi için MERGE deyiminin belgelerine ve örneklerine bakın. Aynı çalışma, ayrı INSERT ve UPDATE işlemleriyle çok adımlı bir saklı yordam çağrısında gerçekleştirilebilse de, MERGE deyimi daha verimlidir. Veritabanı kodu, INSERT ve UPDATE için iki veritabanı çağrısı gerektirmeden doğrudan MERGE deyimini kullanan Transact-SQL çağrıları da oluşturabilir.

Öneri özeti

Aşağıdaki liste, bu makalede ele alınan toplu iş önerilerinin özetini sağlar:

  • Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği uygulamalarının performansını ve ölçeklenebilirliğini artırmak için arabelleğe alma ve toplu işlem kullanın.
  • Toplu işlem/arabelleğe alma ile dayanıklılık arasındaki dengeleri anlayın. Rol hatası sırasında iş açısından kritik verilerin işlenmemiş bir toplu işlemini kaybetme riski, toplu işlemenin performans avantajından daha ağır basabilir.
  • Gecikme süresini azaltmak için veritabanına yapılan tüm çağrıları tek bir veri merkezi içinde tutmayı deneme.
  • Tek bir toplu iş tekniği seçerseniz, tablo değerli parametreler en iyi performansı ve esnekliği sunar.
  • En hızlı ekleme performansı için şu genel yönergeleri izleyin ancak senaryonuzu test edin:
    • 100 satır için < tek bir parametreli INSERT komutu kullanın.
    • < 1000 satır için tablo değerli parametreleri kullanın.
    • = 1000 satır için >SqlBulkCopy kullanın.
  • Güncelleştirme ve silme işlemleri için tablo parametresindeki her satırda doğru işlemi belirleyen saklı yordam mantığına sahip tablo değerli parametreleri kullanın.
  • Toplu iş boyutu yönergeleri:
    • Uygulama ve iş gereksinimleriniz için anlamlı olan en büyük toplu iş boyutlarını kullanın.
    • Büyük toplu işlemlerin performans kazancını geçici veya yıkıcı hata riskleriyle dengeleyin. Yeniden denemelerin veya toplu işteki verilerin kaybının sonucu nedir?
    • Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği'nin bunu reddetmediğini doğrulamak için en büyük toplu iş boyutunu test edin.
    • Toplu iş boyutu veya arabelleğe alma süresi penceresi gibi toplu işlemi denetleyebilen yapılandırma ayarları oluşturun. Bu ayarlar esneklik sağlar. Bulut hizmetini yeniden dağıtmadan üretimdeki toplu işlem davranışını değiştirebilirsiniz.
  • Tek bir veritabanındaki tek bir tabloda çalışan toplu işleri paralel olarak yürütmekten kaçının. Tek bir toplu işlemi birden çok çalışan iş parçacığına bölmeyi seçerseniz, ideal iş parçacığı sayısını belirlemek için testleri çalıştırın. Belirtilmeyen bir eşikten sonra, daha fazla iş parçacığı bunu artırmak yerine performansı düşürür.
  • Daha fazla senaryo için toplu işlem gerçekleştirmenin bir yolu olarak boyut ve zamana göre arabelleğe almayı göz önünde bulundurun.

Sonraki adımlar

Bu makale, toplu işlemle ilgili veritabanı tasarımı ve kodlama tekniklerinin uygulama performansınızı ve ölçeklenebilirliğinizi nasıl geliştirebileceğine odaklanmıştır. Ancak bu, genel stratejinizde yalnızca bir faktördür. Performansı ve ölçeklenebilirliği artırmanın diğer yolları için bkz . Veritabanı performansı kılavuzu ve Elastik havuz için fiyat ve performans konuları.