Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Ketahanan Tertunda di SQL Server 2014

Ketahanan Tertunda adalah fitur terbaru tetapi menarik di SQL Server 2014; nada elevator tingkat tinggi dari fitur ini, cukup sederhana:

    "Perdagangkan ketahanan untuk kinerja."

Beberapa latar belakang pertama. Secara default, SQL Server menggunakan write-ahead log (WAL), yang berarti bahwa perubahan ditulis ke log sebelum diizinkan untuk dilakukan. Dalam sistem di mana penulisan log transaksi menjadi hambatan, dan di mana ada toleransi moderat untuk kehilangan data , Anda sekarang memiliki opsi untuk menangguhkan sementara persyaratan untuk menunggu log flush dan pengakuan. Ini terjadi secara harfiah menghilangkan D dari ACID, setidaknya untuk sebagian kecil data (lebih lanjut tentang ini nanti).

Anda agak sudah membuat pengorbanan ini sekarang. Dalam mode pemulihan penuh, selalu ada beberapa risiko kehilangan data, itu hanya diukur dari segi waktu daripada ukuran. Misalnya, jika Anda mencadangkan log transaksi setiap lima menit, Anda dapat kehilangan data hingga kurang dari 5 menit jika terjadi bencana. Saya tidak berbicara tentang failover sederhana di sini, tetapi katakanlah server benar-benar terbakar atau seseorang tersandung kabel daya – database mungkin tidak dapat dipulihkan dan Anda mungkin harus kembali ke titik waktu pencadangan log terakhir . Dan itu dengan asumsi Anda bahkan menguji cadangan Anda dengan memulihkannya di suatu tempat – jika terjadi kegagalan kritis, Anda mungkin tidak memiliki titik pemulihan yang Anda pikir Anda miliki. Kami cenderung tidak memikirkan skenario ini, tentu saja, karena kami tidak pernah mengharapkan hal buruk™ terjadi.

Cara kerjanya

Ketahanan yang tertunda memungkinkan transaksi tulis untuk terus berjalan seolah-olah log telah di-flush ke disk; pada kenyataannya, penulisan ke disk telah dikelompokkan dan ditangguhkan, untuk ditangani di latar belakang. Transaksinya optimis; itu mengasumsikan bahwa log flush akan terjadi. Sistem menggunakan potongan buffer log sebesar 60KB, dan mencoba mem-flush log ke disk saat blok 60KB ini penuh (paling lambat – hal ini dapat dan sering akan terjadi sebelum itu). Anda dapat mengatur opsi ini di tingkat database, di tingkat transaksi individual, atau – dalam kasus prosedur yang dikompilasi secara asli di OLTP Dalam Memori – di tingkat prosedur. Pengaturan database menang dalam kasus konflik; misalnya, jika database disetel ke dinonaktifkan, mencoba melakukan transaksi menggunakan opsi tunda akan diabaikan begitu saja, tanpa pesan kesalahan. Juga, beberapa transaksi selalu sepenuhnya tahan lama, terlepas dari pengaturan basis data atau pengaturan komit; misalnya, transaksi sistem, transaksi lintas basis data, dan operasi yang melibatkan FileTable, Change Tracking, Change Data Capture, dan Replication.

Pada tingkat basis data, Anda dapat menggunakan:

ALTER DATABASE dbname SET DELAYED_DURABILITY = DISABLED | ALLOWED | FORCED;

Jika Anda menyetelnya ke ALLOWED , ini berarti bahwa setiap transaksi individu dapat menggunakan Ketahanan Tertunda; FORCED artinya semua transaksi yang dapat menggunakan Delayed Durability akan (pengecualian di atas masih relevan dalam kasus ini). Anda mungkin ingin menggunakan ALLOWED daripada FORCED – tetapi yang terakhir dapat berguna dalam kasus aplikasi yang ada di mana Anda ingin menggunakan opsi ini secara keseluruhan dan juga meminimalkan jumlah kode yang harus disentuh. Hal penting yang perlu diperhatikan tentang ALLOWED adalah bahwa transaksi yang tahan lama sepenuhnya mungkin harus menunggu lebih lama, karena transaksi tahan lama akan dipaksakan terlebih dahulu.

Pada tingkat transaksi, Anda dapat mengatakan:

COMMIT TRANSACTION WITH (DELAYED_DURABILITY = ON);

Dan dalam prosedur yang dikompilasi secara native OLTP Dalam Memori, Anda dapat menambahkan opsi berikut ke BEGIN ATOMIC blok:

BEGIN ATOMIC WITH (DELAYED_DURABILITY = ON, ...)

Pertanyaan umum adalah seputar apa yang terjadi dengan penguncian dan isolasi semantik. Tidak ada yang berubah, sungguh. Penguncian dan pemblokiran masih terjadi, dan transaksi dilakukan dengan cara dan aturan yang sama. Satu-satunya perbedaan adalah, dengan membiarkan komit terjadi tanpa menunggu log mengalir ke disk, semua kunci terkait akan dilepaskan lebih cepat.

Kapan Anda Harus Menggunakannya

Selain manfaat yang Anda dapatkan dari mengizinkan transaksi untuk dilanjutkan tanpa menunggu penulisan log terjadi, Anda juga mendapatkan lebih sedikit penulisan log dengan ukuran yang lebih besar. Ini dapat bekerja dengan sangat baik jika sistem Anda memiliki proporsi transaksi tinggi yang sebenarnya lebih kecil dari 60KB, dan terutama ketika disk log lambat (walaupun saya menemukan manfaat serupa pada SSD dan HDD tradisional). Ini tidak berjalan dengan baik jika transaksi Anda, sebagian besar, lebih besar dari 60KB, jika biasanya berjalan lama, atau jika Anda memiliki throughput tinggi dan konkurensi tinggi. Apa yang dapat terjadi di sini adalah Anda dapat mengisi seluruh buffer log sebelum flush selesai, yang berarti mentransfer waktu tunggu Anda ke sumber daya yang berbeda dan, pada akhirnya, tidak meningkatkan kinerja yang dirasakan oleh pengguna aplikasi.

Dengan kata lain, jika log transaksi Anda saat ini tidak menjadi hambatan, jangan aktifkan fitur ini. Bagaimana Anda bisa tahu jika log transaksi Anda saat ini menjadi hambatan? Indikator pertama adalah WRITELOG tinggi menunggu, terutama jika digabungkan dengan PAGEIOLATCH_** . Paul Randal (@PaulRandal) memiliki rangkaian empat bagian yang hebat dalam mengidentifikasi masalah log transaksi, serta mengonfigurasi untuk kinerja yang optimal:

  • Memotong Lemak Log Transaksi
  • Memotong Lebih Banyak Lemak Log Transaksi
  • Masalah Konfigurasi Log Transaksi
  • Pemantauan Log Transaksi

Lihat juga posting blog ini dari Kimberly Tripp (@KimberlyLTripp), 8 Langkah untuk Throughput Log Transaksi yang Lebih Baik, dan posting blog tim SQL CAT, Mendiagnosis Masalah Kinerja Log Transaksi dan Batas Manajer Log.

Penyelidikan ini dapat membawa Anda pada kesimpulan bahwa Ketahanan Tertunda layak untuk dilihat; mungkin tidak. Menguji beban kerja Anda akan menjadi cara paling andal untuk mengetahui dengan pasti. Seperti banyak tambahan lain di versi terbaru SQL Server (*cough* Hekaton ), fitur ini TIDAK dirancang untuk meningkatkan setiap beban kerja – dan seperti disebutkan di atas, fitur ini sebenarnya dapat memperburuk beberapa beban kerja. Lihat posting blog ini oleh Simon Harvey untuk beberapa pertanyaan lain yang harus Anda tanyakan pada diri sendiri tentang beban kerja Anda untuk menentukan apakah layak untuk mengorbankan beberapa daya tahan untuk mencapai kinerja yang lebih baik.

Berpotensi kehilangan data

Saya akan menyebutkan ini beberapa kali, dan menambahkan penekanan setiap kali saya melakukannya:Anda harus toleran terhadap kehilangan data . Di bawah disk yang berkinerja baik, jumlah maksimum yang Anda harapkan untuk hilang dalam bencana – atau bahkan shutdown yang terencana dan anggun – adalah hingga satu blok penuh (60KB). Namun, dalam kasus di mana subsistem I/O Anda tidak dapat mengikuti, ada kemungkinan bahwa Anda bisa kehilangan sebanyak buffer log (~7MB).

Untuk memperjelas, dari dokumentasi (penekanan milik saya):

Untuk ketahanan yang tertunda, tidak ada perbedaan antara shutdown yang tidak terduga dan shutdown/restart SQL Server yang diharapkan . Seperti peristiwa bencana, Anda harus merencanakan kehilangan data . Dalam shutdown/restart yang direncanakan, beberapa transaksi yang belum ditulis ke disk mungkin pertama kali disimpan ke disk, tetapi Anda tidak boleh merencanakannya. Rencanakan seolah-olah shutdown/restart, baik direncanakan atau tidak direncanakan, kehilangan data yang sama seperti peristiwa bencana.

Jadi, sangat penting bagi Anda untuk menimbang risiko kehilangan data dengan kebutuhan Anda untuk mengurangi masalah kinerja log transaksi. Jika Anda menjalankan bank atau apa pun yang berhubungan dengan uang, mungkin jauh lebih aman dan lebih tepat bagi Anda untuk memindahkan log Anda ke disk yang lebih cepat daripada melempar dadu menggunakan fitur ini. Jika Anda mencoba meningkatkan waktu respons di aplikasi Ruang Obrolan Gamerz Web Anda, mungkin risikonya tidak terlalu parah.

Anda dapat mengontrol perilaku ini sampai tingkat tertentu untuk meminimalkan risiko kehilangan data. Anda dapat memaksa semua transaksi tahan lama yang tertunda untuk dipindahkan ke disk dengan salah satu dari dua cara:

  1. Lakukan semua transaksi yang tahan lama.
  2. Hubungi sys.sp_flush_log secara manual.

Ini memungkinkan Anda untuk kembali mengontrol kehilangan data dalam hal waktu, bukan ukuran; Anda dapat menjadwalkan flush setiap 5 detik, misalnya. Tetapi Anda akan ingin menemukan sweet spot Anda di sini; pembilasan terlalu sering dapat mengimbangi manfaat Ketahanan Tertunda sejak awal. Bagaimanapun, Anda tetap harus toleran terhadap kehilangan data , meskipun hanya bernilai detik.

Anda akan berpikir bahwa CHECKPOINT mungkin membantu di sini, tetapi operasi ini sebenarnya tidak menjamin secara teknis log akan di-flush ke disk.

Interaksi dengan HA/DR

Anda mungkin bertanya-tanya bagaimana Ketahanan Tertunda berfungsi dengan fitur HA/DR seperti pengiriman log, replikasi, dan Grup Ketersediaan. Dengan sebagian besar ini berfungsi tidak berubah. Pengiriman dan replikasi log akan memutar ulang catatan log yang telah dikeraskan, sehingga potensi kehilangan data yang sama ada di sana. Dengan AG dalam mode asinkron, kami tidak menunggu pengakuan sekunder, sehingga akan berperilaku sama seperti hari ini. Namun, dengan sinkron, kami tidak dapat melakukan pada primer sampai transaksi dilakukan dan dikeraskan ke log jarak jauh. Bahkan dalam skenario itu kita mungkin mendapat keuntungan secara lokal dengan tidak harus menunggu log lokal untuk menulis, kita masih harus menunggu aktivitas jarak jauh. Jadi dalam skenario itu ada lebih sedikit manfaat, dan berpotensi tidak ada; kecuali mungkin dalam skenario yang jarang terjadi di mana disk log primer sangat lambat dan disk log sekunder sangat cepat. Saya menduga kondisi yang sama berlaku untuk pencerminan sinkronisasi/asinkron, tetapi Anda tidak akan mendapatkan komitmen resmi dari saya tentang cara kerja fitur baru yang mengilap dengan fitur yang sudah usang. :-)

Pengamatan Kinerja

Ini tidak akan banyak posting di sini jika saya tidak menunjukkan beberapa pengamatan kinerja yang sebenarnya. Saya menyiapkan 8 database untuk menguji efek dari dua pola beban kerja yang berbeda dengan atribut berikut:

  • Model pemulihan:sederhana vs. penuh
  • Lokasi log:SSD vs. HDD
  • Daya tahan:tertunda vs. sepenuhnya tahan lama

Saya benar-benar malas efisien tentang hal semacam ini. Karena saya ingin menghindari pengulangan operasi yang sama dalam setiap database, saya membuat tabel berikut untuk sementara di model :

USE model;
GO
 
CREATE TABLE dbo.TheTable
(
  TheID INT IDENTITY(1,1) PRIMARY KEY,
  TheDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  RowGuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()
);

Kemudian saya membangun satu set perintah SQL dinamis untuk membangun 8 database ini, daripada membuat database satu per satu dan kemudian mengacaukan pengaturannya:

-- C and D are SSD, G is HDD
 
DECLARE @sql NVARCHAR(MAX) = N'';
 
;WITH l AS (SELECT l FROM (VALUES('D'),('G')) AS l(l)),
r AS (SELECT r FROM (VALUES('FULL'),('SIMPLE')) AS r(r)),
d AS (SELECT d FROM (VALUES('FORCED'),('DISABLED')) AS d(d)),
x AS (SELECT l.l, r.r, d.d, n = CONVERT(CHAR(1),ROW_NUMBER() OVER 
  (ORDER BY d.d DESC, l.l)) FROM l CROSS JOIN r CROSS JOIN d)
SELECT @sql += N'
CREATE DATABASE dd' + n + ' ON '
+ '(name = ''dd' + n + '_data'','
+ ' filename = ''C:\SQLData\dd' + n + '.mdf'', size = 1024MB)
LOG ON (name = ''dd' + n + '_log'','
+ ' filename = ''' + l + ':\SQLLog\dd' + n + '.ldf'', size = 1024MB);
  ALTER DATABASE dd' + n + ' SET RECOVERY ' + r  + ';
  ALTER DATABASE dd' + n + ' SET DELAYED_DURABILITY = ' + d + ';'
FROM x ORDER BY d, l;
 
PRINT @sql;
-- EXEC sp_executesql @sql;

Jangan ragu untuk menjalankan kode ini sendiri (dengan EXEC masih berkomentar) untuk melihat bahwa ini akan membuat 4 database dengan Delayed Durability OFF (dua dalam pemulihan LENGKAP, dua dalam SEDERHANA, masing-masing dengan log pada disk lambat, dan masing-masing dengan log on SSD). Ulangi pola itu untuk 4 database dengan Delayed Durability FORCED – Saya melakukan ini untuk menyederhanakan kode dalam pengujian, daripada mencerminkan apa yang akan saya lakukan dalam kehidupan nyata (di mana saya mungkin ingin memperlakukan beberapa transaksi sebagai hal yang kritis, dan beberapa sebagai, baik, kurang kritis).

Untuk pemeriksaan kewarasan, saya menjalankan kueri berikut untuk memastikan bahwa database memiliki matriks atribut yang tepat:

SELECT d.name, d.recovery_model_desc, d.delayed_durability_desc, 
  log_disk = CASE WHEN mf.physical_name LIKE N'D%' THEN 'SSD' else 'HDD' END
FROM sys.databases AS d
INNER JOIN sys.master_files AS mf
ON d.database_id = mf.database_id
WHERE d.name LIKE N'dd[1-8]'
AND mf.[type] = 1; -- log

Hasil:

nama model_pemulihan ketahanan_tertunda log_disk dd1 SELENGKAPNYA PAKSA SSD dd2 SEDERHANA PAKSA SSD dd3 SELENGKAPNYA PAKSA HDD dd4 SEDERHANA PAKSA HDD dd5 SELENGKAPNYA DINONAKTIFKAN SSD dd6 SEDERHANA DINONAKTIFKAN SSD dd7 SELENGKAPNYA DINONAKTIFKAN HDD dd8 SEDERHANA DINONAKTIFKAN HDD

Konfigurasi yang relevan dari 8 database pengujian

Saya juga menjalankan pengujian dengan rapi beberapa kali untuk memastikan bahwa file data 1 GB dan file log 1 GB akan cukup untuk menjalankan seluruh rangkaian beban kerja tanpa memasukkan peristiwa pertumbuhan otomatis ke dalam persamaan. Sebagai praktik terbaik, saya secara rutin berusaha keras untuk memastikan sistem pelanggan memiliki cukup ruang yang dialokasikan (dan peringatan yang tepat terpasang) sehingga tidak ada peristiwa pertumbuhan yang terjadi pada waktu yang tidak terduga. Di dunia nyata saya tahu ini tidak selalu terjadi, tapi ini ideal.

Saya mengatur sistem yang akan dipantau dengan SQL Sentry – ini akan memungkinkan saya untuk dengan mudah menunjukkan sebagian besar metrik kinerja yang ingin saya soroti. Tetapi saya juga membuat tabel sementara untuk menyimpan metrik batch termasuk durasi dan keluaran yang sangat spesifik dari sys.dm_io_virtual_file_stats:

SELECT test = 1, cycle = 1, start_time = GETDATE(), * 
INTO #Metrics 
FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2) WHERE 1 = 0;

Ini akan memungkinkan saya untuk merekam waktu mulai dan selesai setiap batch individu, dan mengukur delta di DMV antara waktu mulai dan waktu akhir (hanya dapat diandalkan dalam kasus ini karena saya tahu saya satu-satunya pengguna di sistem).

    Banyak transaksi kecil

    Tes pertama yang ingin saya lakukan adalah banyak transaksi kecil. Untuk setiap database, saya ingin mendapatkan 500.000 batch terpisah dari satu sisipan masing-masing:

    INSERT #Metrics SELECT 1, 1, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);
    GO
    INSERT dbo.TheTable DEFAULT VALUES;
    GO 500000
    INSERT #Metrics SELECT 1, 2, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);

    Ingat, saya mencoba untuk malas efisien tentang hal semacam ini. Jadi untuk menghasilkan kode untuk semua 8 database, saya menjalankan ini:

    ;WITH x AS 
    (
      SELECT TOP (8) number FROM master..spt_values 
      WHERE type = N'P' ORDER BY number
    )
    SELECT CONVERT(NVARCHAR(MAX), N'') + N'
    INSERT #Metrics SELECT 1, 1, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2);
    GO
    INSERT dbo.TheTable DEFAULT VALUES;
    GO 500000
    INSERT #Metrics SELECT 1, 2, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2);'
    FROM x;

    Saya menjalankan tes ini dan kemudian melihat #Metrics tabel dengan kueri berikut:

    SELECT 
      [database] = db_name(m1.database_id),
      num_writes = m2.num_of_writes - m1.num_of_writes, 
      write_bytes = m2.num_of_bytes_written - m1.num_of_bytes_written,
      bytes_per_write = (m2.num_of_bytes_written - m1.num_of_bytes_written)*1.0
        /(m2.num_of_writes - m1.num_of_writes),
      io_stall_ms = m2.io_stall_write_ms - m1.io_stall_write_ms,
      m1.start_time,
      end_time = m2.start_time,
      duration = DATEDIFF(SECOND, m1.start_time, m2.start_time)
    FROM #Metrics AS m1
    INNER JOIN #Metrics AS m2
    ON m1.database_id = m2.database_id
    WHERE m1.cycle = 1 AND m2.cycle = 2
    AND m1.test = 1 AND m2.test = 1;

    Ini menghasilkan hasil berikut (dan saya mengkonfirmasi melalui beberapa tes bahwa hasilnya konsisten):

    database menulis byte byte/tulis io_stall_ms waktu_mulai akhir_waktu durasi (detik)
    dd1 8.068 261.894.656 32.460,91 6.232 26-04-2014 17:20:00 26-04-2014 17:21:08 68
    dd2 8.072 261.682.688 32.418.56 2,740 26-04-2014 17:21:08 26-04-2014 17:22:16 68
    dd3 8,246 262.254.592 31,803,85 3.996 26-04-2014 17:22:16 26-04-2014 17:23:24 68
    dd4 8.055 261.688.320 32.487,68 4,231 26-04-2014 17:23:24 26-04-2014 17:24:32 68
    dd5 500.012 526.448.640 1.052.87 35.593 26-04-2014 17:24:32 26-04-2014 17:26:32 120
    dd6 500.014 525.870.080 1.051.71 35.435 26-04-2014 17:26:32 26-04-2014 17:28:31 119
    dd7 500.015 526.120.448 1.052.20 50,857 26-04-2014 17:28:31 26-04-2014 17:30:45 134
    dd8 500.017 525.886.976 1.051.73 49,680 26-04-2014 17:30:45 26-04-2014 17:32:58 133

    Transaksi kecil:Durasi dan hasil dari sys.dm_io_virtual_file_stats

    Pasti ada beberapa pengamatan menarik di sini:

    • Jumlah operasi penulisan individual sangat kecil untuk database Ketahanan Tertunda (~60X untuk tradisional).
    • Jumlah total byte yang ditulis dipotong menjadi dua menggunakan Delayed Durability (saya kira karena semua penulisan dalam kasus tradisional mengandung banyak ruang yang terbuang).
    • Jumlah byte per penulisan jauh lebih tinggi untuk Ketahanan Tertunda. Ini tidak terlalu mengejutkan, karena seluruh tujuan dari fitur ini adalah untuk menggabungkan penulisan bersama dalam kumpulan yang lebih besar.
    • Total durasi I/O stall tidak stabil, tetapi kira-kira urutan besarnya lebih rendah untuk Delayed Durability. Kios di bawah transaksi yang sepenuhnya tahan lama jauh lebih sensitif terhadap jenis disk.
    • Jika ada yang belum meyakinkan Anda sejauh ini, kolom durasi sangat jitu. Batch yang sepenuhnya tahan lama yang membutuhkan waktu dua menit atau lebih dipotong hampir setengahnya.

    Kolom waktu mulai/berakhir memungkinkan saya untuk fokus pada dasbor Performance Advisor untuk periode yang tepat di mana transaksi ini terjadi, di mana kita dapat menggambar banyak indikator visual tambahan:


    Dasbor SQL Sentry – klik untuk memperbesar

    Pengamatan lebih lanjut di sini:

    • Pada beberapa grafik, Anda dapat melihat dengan jelas kapan porsi Ketahanan Non-Delayed dari batch mengambil alih (~5:24:32 PM).
    • Tidak ada dampak yang terlihat pada CPU atau memori saat menggunakan Ketahanan Tertunda.
    • Anda dapat melihat dampak luar biasa pada kumpulan/transaksi per detik di grafik pertama di bawah Aktivitas SQL Server.
    • SQL Server menunggu melalui atap ketika transaksi yang sepenuhnya tahan lama dimulai. Ini hampir secara eksklusif terdiri dari WRITELOG menunggu, dengan sejumlah kecil PAGEIOLOATCH_EX dan PAGEIOLATCH_UP menunggu ukuran yang baik.
    • Jumlah total log flush selama operasi Ketahanan Tertunda cukup kecil (rendah 100 detik/detik), sementara ini melonjak menjadi lebih dari 4.000/detik untuk perilaku tradisional (dan sedikit lebih rendah untuk durasi pengujian HDD).
    Transaksi lebih sedikit dan lebih besar

    Untuk pengujian berikutnya, saya ingin melihat apa yang akan terjadi jika kami melakukan lebih sedikit operasi, tetapi memastikan setiap pernyataan memengaruhi jumlah data yang lebih besar. Saya ingin batch ini dijalankan terhadap setiap database:

    CREATE TABLE dbo.Rnd
    (
      batch TINYINT,
      TheID INT
    );
     
    INSERT dbo.Rnd SELECT TOP (1000) 1, TheID FROM dbo.TheTable ORDER BY NEWID();
    INSERT dbo.Rnd SELECT TOP (10)   2, TheID FROM dbo.TheTable ORDER BY NEWID();
    INSERT dbo.Rnd SELECT TOP (300)  3, TheID FROM dbo.TheTable ORDER BY NEWID();
    GO
     
    INSERT #Metrics SELECT 1, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);
    GO
    UPDATE t SET TheDate = DATEADD(MINUTE, 1, TheDate)
      FROM dbo.TheTable AS t
      INNER JOIN dbo.Rnd AS r
      ON t.TheID = r.TheID
      WHERE r.batch = 1;
    GO 10000
    UPDATE t SET RowGuid = NEWID()
      FROM dbo.TheTable AS t
      INNER JOIN dbo.Rnd AS r
      ON t.TheID = r.TheID
      WHERE r.batch = 2;
    GO 10000
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID   FROM dbo.Rnd WHERE batch = 3);
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID+1 FROM dbo.Rnd WHERE batch = 3);
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID-1 FROM dbo.Rnd WHERE batch = 3);
    GO
    INSERT #Metrics SELECT 2, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);

    Jadi sekali lagi saya menggunakan metode lazy untuk menghasilkan 8 salinan skrip ini, satu per database:

    ;WITH x AS (SELECT TOP (8) number FROM master..spt_values WHERE type = N'P' ORDER BY number)
    SELECT N'
    USE dd' + RTRIM(Number+1) + ';
    GO
     
    CREATE TABLE dbo.Rnd
    (
      batch TINYINT,
      TheID INT
    );
     
    INSERT dbo.Rnd SELECT TOP (1000) 1, TheID FROM dbo.TheTable ORDER BY NEWID();
    INSERT dbo.Rnd SELECT TOP (10)   2, TheID FROM dbo.TheTable ORDER BY NEWID();
    INSERT dbo.Rnd SELECT TOP (300)  3, TheID FROM dbo.TheTable ORDER BY NEWID();
    GO
     
    INSERT #Metrics SELECT 2, 1, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + ''', 2);
    GO
    UPDATE t SET TheDate = DATEADD(MINUTE, 1, TheDate)
      FROM dbo.TheTable AS t
      INNER JOIN dbo.rnd AS r
      ON t.TheID = r.TheID
      WHERE r.cycle = 1;
    GO 10000
    UPDATE t SET RowGuid = NEWID()
      FROM dbo.TheTable AS t
      INNER JOIN dbo.rnd AS r
      ON t.TheID = r.TheID
      WHERE r.cycle = 2;
    GO 10000
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID   FROM dbo.rnd WHERE cycle = 3);
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID+1 FROM dbo.rnd WHERE cycle = 3);
    DELETE dbo.TheTable WHERE TheID IN (SELECT TheID-1 FROM dbo.rnd WHERE cycle = 3);
    GO
    INSERT #Metrics SELECT 2, 2, GETDATE(), * 
      FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2);'
    FROM x;

    Saya menjalankan kumpulan ini, lalu mengubah kueri menjadi #Metrics di atas untuk melihat tes kedua, bukan yang pertama. Hasilnya:

    database menulis byte byte/tulis io_stall_ms waktu_mulai akhir_waktu durasi (detik)
    dd1 20.970 1.271.911.936 60,653.88 12.577 26-04-2014 17:41:21 26-04-2014 17:43:46 145
    dd2 20.997 1.272.145.408 60.587,00 14.698 26-04-2014 17:43:46 26-04-2014 17:46:11 145
    dd3 20.973 1.272.982.016 60,696.22 12.085 26-04-2014 17:46:11 26-04-2014 17:48:33 142
    dd4 20.958 1.272.064.512 60.695,89 11.795 26-04-2014 17:48:33 26-04-2014 17:50:56 143
    dd5 30.138 1.282.231.808 42.545,35 7.402 26-04-2014 17:50:56 26-04-2014 17:53:23 147
    dd6 30.138 1.282.260.992 42.546,31 7.806 26-04-2014 17:53:23 26-04-2014 17:55:53 150
    dd7 30.129 1.281.575.424 42.536,27 9.888 26-04-2014 17:55:53 26-04-2014 17:58:25 152
    dd8 30.130 1.281.449.472 42.530,68 11,452 26-04-2014 17:58:25 26-04-2014 18:00:55 150

    Transaksi lebih besar:Durasi dan hasil dari sys.dm_io_virtual_file_stats

    Kali ini, dampak Delayed Durability tidak terlalu terlihat. Kami melihat jumlah operasi tulis yang sedikit lebih kecil, dengan jumlah byte per penulisan yang sedikit lebih besar, dengan total byte yang ditulis hampir sama. Dalam kasus ini kita benar-benar melihat bahwa I/O stall lebih tinggi untuk Delayed Durability, dan kemungkinan ini menjelaskan fakta bahwa durasinya juga hampir sama.

    Dari dasbor Performance Advisor, kami memiliki beberapa kesamaan dengan pengujian sebelumnya, dan beberapa perbedaan mencolok juga:


    Dasbor SQL Sentry – klik untuk memperbesar

    Salah satu perbedaan besar untuk ditunjukkan di sini adalah bahwa delta dalam statistik tunggu tidak begitu jelas seperti pada tes sebelumnya – masih ada frekuensi WRITELOG yang jauh lebih tinggi. menunggu batch yang sepenuhnya tahan lama, tetapi tidak mendekati level yang terlihat dengan transaksi yang lebih kecil. Hal lain yang dapat Anda temukan segera adalah bahwa dampak yang diamati sebelumnya pada batch dan transaksi per detik tidak lagi ada. Dan terakhir, meskipun terdapat lebih banyak log flush dengan transaksi yang sepenuhnya tahan lama daripada saat tertunda, perbedaan ini jauh lebih kecil dibandingkan dengan transaksi yang lebih kecil.

Kesimpulan

Harus jelas bahwa ada jenis beban kerja tertentu yang mungkin sangat diuntungkan dari Ketahanan Tertunda – dengan syarat, tentu saja, Anda memiliki toleransi terhadap kehilangan data . Fitur ini tidak terbatas pada In-Memory OLTP, tersedia di semua edisi SQL Server 2014, dan dapat diimplementasikan dengan sedikit atau tanpa perubahan kode. Ini tentu bisa menjadi teknik yang ampuh jika beban kerja Anda dapat mendukungnya. Namun sekali lagi, Anda perlu menguji beban kerja Anda untuk memastikan bahwa itu akan mendapat manfaat dari fitur ini, dan juga sangat mempertimbangkan apakah ini meningkatkan eksposur Anda terhadap risiko kehilangan data.

Selain itu, ini mungkin tampak bagi kerumunan SQL Server seperti ide baru yang segar, tetapi sebenarnya Oracle memperkenalkan ini sebagai "Asynchronous Commit" pada tahun 2006 (lihat COMMIT WRITE ... NOWAIT seperti yang didokumentasikan di sini dan di blog pada tahun 2007). Dan ide itu sendiri telah ada selama hampir 3 dekade; lihat riwayat singkat Hal Berenson tentang sejarahnya.

Lain kali

Satu ide yang saya perjuangkan adalah mencoba meningkatkan kinerja tempdb dengan memaksa Ketahanan Tertunda di sana. Satu properti khusus tempdb yang membuatnya menjadi kandidat yang menggoda adalah sifatnya yang sementara – apa pun di tempdb dirancang, secara eksplisit, untuk dapat dilemparkan setelah berbagai macam peristiwa sistem. Saya mengatakan ini sekarang tanpa tahu apakah ada bentuk beban kerja di mana ini akan berjalan dengan baik; tapi saya berencana untuk mencobanya, dan jika saya menemukan sesuatu yang menarik, Anda pasti akan mempostingnya di sini.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apakah mungkin untuk memilih data server sql menggunakan posisi ordinal kolom

  2. Hindari 4 Kesalahan Umum DBA Ini

  3. Kueri berparameter mengharapkan parameter yang tidak disediakan

  4. Mengonversi hasil Pilih menjadi skrip Sisipkan - SQL Server

  5. Memanggil API dari prosedur tersimpan SQL Server