Aracılığıyla paylaş


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 için 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'daki 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.

toplu işlem Azure SQL Veritabanı ve Azure SQL Yönetilen Örneği için 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önetmek zorunda olmadığınızdı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şlem 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östermek içindir. 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 DTU tabanlı satın alma modelini veya sanal çekirdek satın alma modelini 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.

Hareketler

İş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. Aşağıda 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. Microsoft Azure veri merkezinin dışından Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği 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 adlı MyTableTypebir tablo türü oluşturur.

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

Kodda, tablo türünün tam olarak aynı adlara ve türlere sahip bir DataTable oluşturursunuz. Bunu DataTable bir metin sorgusunda veya saklı yordam çağrısında bir parametre olarak iletin. 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 parametresinden @TestTvpsatırlar ekler. Daha önce oluşturulan DataTable nesne yöntemiyle bu parametreye SqlCommand.Parameters.Add 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ğıda kullanılan Transact-SQL komutu, SimpleTestTableType tablo-değerli parametreyi 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 nesne bildirimini aşağıdakiyle değiştirin SqlCommand .

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ü diğer seçeneklerden 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 Yirmi beş
100 338 51
1000 2615 382
10.000 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 1.000 işlem veri merkezinin dışında 129 saniye ve veri merkezinin içinden 21 saniye sürmüştü. Ancak tablo değerli parametrelerle 1.000 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 sınıfını SqlBulkCopy kullanabilir. SqlBulkCopy işlevinde komut satırı aracına veya Bcp.exeTransact-SQL deyimine BULK INSERTbenzer. Aşağıdaki kod örneği, kaynak DataTable, tablosundaki satırların hedef tabloya MyTabletoplu 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. Table-Valued parametreleri ile BULK INSERT işlemlerinin karşılaştırıldığı Table-Valued Parametreler makalesindeki tabloya bakın.

Aşağıdaki geçici test sonuçları ile SqlBulkCopy 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
10.000 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ına kıyasla daha iyi performans gösterdi. Ancak, SqlBulkCopy 1.000 ve 10.000 satırlık testler için tablo değerli parametrelerden daha hızlı% 12-31 gerçekleştirildi. Tablo değerli parametreler gibi, SqlBulkCopy toplu olmayan işlemlerin performansıyla karşılaştırıldığında toplu eklemeler için iyi bir seçenektir.

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 2.100 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 Yirmi beş
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'den az satır içeren 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.

Veri Adaptörü

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

Entity Framework (varlık çerçevesi)

Entity Framework Core toplu işlemi destekler.

XML

Tamlık açısından, XML'yi bir toplu iş stratejisi olarak ele almanın önemli olduğunu düşünüyoruz. 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 penceresi içinde veritabanına göndermeden önce arabelleğe aldığınızda risk artmaktadı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, 1.000 satır eklemek istediğiniz bir senaryo düşünün. Aşağıdaki tabloda, daha küçük gruplara bölündüğünde 1.000 satır eklemek için tablo türündeki parametreleri kullanmanın ne kadar sürdüğü gösterilmektedir.

Toplu iş boyutu Yinelemeler Tablo değerli parametreler (ms)
1000 1 347
beş yüz 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.

1.000 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 toplu işlemi kısıtlamak ve işlemeyi reddetmektir. 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 gruba 1.000 satır eklemeyi çalışır. 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 biraz performans artışı görebilirsiniz. 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 özelliğini 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.

Eğer tablo değerli parametreler bir saklı yordam kullanıyorsa, yordamın başında SET NOCOUNT ON komutunu kullanabilirsiniz. Bu deyim, yordamdaki etkilenen satırların sayısının döndürülmesi gizlenir. Ancak testlerimizde, kullanımının SET NOCOUNT ON herhangi bir etkisi yoktu veya performansı düşürmüştü. Test saklı yordamı, tablo değerli parametresinden tek INSERT bir komutla basitti. Daha karmaşık saklı yordamların bu ifadeden yarar sağlaması mümkün olabilir. Ancak SET NOCOUNT ON'i saklı yordamınıza eklemenin performansı otomatik olarak artırdığını varsaymayın. Etkinin ne olduğunu anlamak için saklı yordamınızı SET NOCOUNT ON ifadesi ile birlikte ve olmadan 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 1.000 öğ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 geçici olarak depolamakla sorumludur. RecordUserNavigationEntry yöntemi, bir "OnAdded" olayı oluşturarak yanıt verir. 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 metodu ile bu gözlemlenebilir koleksiyona abone olur. Aşırı yükleme, arabelleğin her 20 saniyede bir veya 1.000 girdide 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 hem NavHistoryDataEventArgs 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 hem NavHistoryDataEventArgs 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 NavHistoryDataMonitor bir nesne oluşturur. Bir kullanıcı bir sayfaya her eriştiğinde, uygulama öğesini NavHistoryDataMonitorçağırır. RecordUserNavigationEntry yöntem. 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. Basitleştirilmiş bir PurchaseOrder tablosunu ve ilişkili OrderDetail tablosunu düşünün. Aşağıdaki Transact-SQL dört sütunlu PurchaseOrder tabloyu oluşturur: OrderID, OrderDate, CustomerIDve 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 tabloda bulunur. Aşağıdaki Transact-SQL beş sütunlu PurchaseOrderDetail tabloyu oluşturur: OrderID, OrderDetailID, ProductID, UnitPriceve 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 ));

OrderID tablodaki sütun, PurchaseOrderDetail tablosundan bir siparişe referans vermelidir. 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ğerleri depolar. Bu sipariş tanımlayıcıları, geçici OrderID değerlerinin @orders ve @details tablo değerli parametrelerdeki değerlerinden farklıdır. Bu nedenle, @IdentityLink tablosu daha sonra OrderID parametresindeki @orders değerlerini OrderID tablosunun yeni satırları için gerçek PurchaseOrder değerlerle bağlar. Bu adımdan sonra, @IdentityLink tablo, sipariş ayrıntılarının yabancı anahtar kısıtlamasını karşılayan doğru OrderID ile daha kolay bir şekilde eklenmesini sağlayabilir.

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 öğesinin nasıl çağrılacağını göstermektedir.

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 değer kümesi OrderID kullanmasına olanak tanır. Bu geçici OrderID değerler toplu iş ilişkilerini açıklar, ancak gerçek OrderID değerler 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österilmiyor.

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 komut kullanın.
    • < 1.000 satır için tablo değerli parametreleri kullanın.
    • 1000 satır varsa >, kullanın SqlBulkCopy.
  • 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.