SQL: CPU veya IO değilse INSERT'leri yavaşlatan nedir?


19

Yazma ağırlıklı bir ürün için veritabanımız var. Yeni bir sunucuya SSD ile yardımcı olduk. Şaşırtıcı bir şekilde, eklemeler çok daha yavaş depolanan eski makinemizden daha hızlı değildi. Kıyaslama sırasında SQL Server işlemi tarafından sergilenen G / Ç oranının çok düşük olduğunu fark ettik.

Örneğin , döngüde bir BEGIN TRAN ve COMMIT eklediğim dışında , bu sayfada bulunan komut dosyasını çalıştırdım . En iyi ihtimalle disk kullanımı 7Mb / s'ye ulaşırken, CPU% 5'e neredeyse hiç dokunmadı. Sunucuda 64Gb kurulu ve 10 kullanıyor. Toplam çalışma süresi ilk arama için 2 dakika 15 saniye, sonraki aramalar için yaklaşık 1 dakika idi. Veritabanı basit kurtarma aşamasındadır ve test sırasında boştadır. Her çağrı arasına masayı bıraktım.

Bu kadar basit bir komut dosyası neden bu kadar yavaş? Donanım neredeyse hiç kullanılmıyor. Hem özel disk karşılaştırma araçları hem de SQLIO, SSD'nin hem okuma hem de yazma için 500Mb / s'den daha yüksek hızlarda doğru performans gösterdiğini gösterir. Rasgele yazmaların sıralı yazmalardan daha yavaş olduğunu anlıyorum, ancak kümelenmiş indeksleme olmayan bir tabloya böyle basit bir eklentinin çok daha hızlı olmasını beklerim.

Sonuçta senaryomuz çok daha karmaşık, ama önce basit bir vakayı anlamam gerektiğini hissediyorum. Özetle, uygulamamız eski verileri siler, daha sonra yeni verileri hazırlama tablolarına kopyalamak için SqlBulkCopy kullanır, bazı filtreleme gerçekleştirir ve son olarak verileri son tablolara kopyalamak için MERGE ve / veya INSERT INTO kullanır.

-> DÜZENLEME 1: Martin Smith ile bağlantılı prosedürü takip ettim ve şu sonucu aldım:

[Wait Type]  [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO          5008              46735                 46587        148
LOGBUFFER           901               5994                  5977         17
PAGELATCH_UP        40                866                   865          1
SOS_SCHEDULER_YIELD 53279             219                   121          98
WRITELOG            5                 145                   145          0
PAGEIOLATCH_UP      4                 58                    58           0
LATCH_SH            5                 0                     0            0

NETWORK_IO, SQL dosyaları dışında hiçbir yerde görüntülenecek ve aktarılacak hiçbir veri olmadığını düşünerek, çoğu zaman alır. NETWORK_IO türü tüm ES'leri içeriyor mu?

-> EDIT 2: Bir 20Gb RAM disk oluşturdum ve oradan bir veritabanı monte ettim. SSD'de geçirdiğim en iyi zaman 48 saniye, RAM disk ile 37 saniyeye düştü. NETWORK_IO hala en büyük bekleme. RAM diskine maksimum yazma hızı yaklaşık 250Mb / s iken saniyede çok gigabayt yapabiliyordu. Hala fazla CPU kullanmıyordu, SQL'i tutan ne?



3
NETWORK_IOmesajları geri gönderiliyor 3000000 "etkilenen 1 satır (lar)" dan olabilir. SET NOCOUNT ONSenaryoya eklemeyi denedin mi?
Martin Smith

Evet, NOCOUNT ekledim.
Şubat'ta Djof

2
Garip. O zamanlar ağ faaliyeti konusunda fazla bir şey beklemiyordum. Çalışmalar arasında eski genişletilmiş etkinlik dosyalarını sildiniz mi? Onları okuyan komut dosyası joker karakter kullanır, EE_WaitStats*.xelböylece eskileri sonuçlarınızı kirletir.
Martin Smith

İyi arama, sonuçları yarın güncelleyeceğim.
Djof

Yanıtlar:


9

Bunun eski bir soru olduğunu biliyorum, ancak bu hala arama yapanlara yardımcı olabilir ve bu arada bir ortaya çıkan bir sorundur.

Herhangi bir kaynak darboğazını görmeden bir performans tavanına vurmanın ana nedeni, tek oturumda tek bir iş parçacığında işlenmenin mümkün olan sınırına ulaşmış olmanızdır. Döngü paralel olarak işlenmez, ancak tüm ekler seri olarak yapılır.

Benim durumumda, 3 milyon satır eklemek 36 saniye sürüyor. Bu, satır başına 36/30000000 = 0,000012 saniye anlamına gelir. Oldukça hızlı. Sistemimde, gerekli tüm adımları uygulamak 0.000012 alır.

Daha hızlı yapmanın tek yolu paralel olarak ikinci bir oturum başlatmaktır.

Paralel olarak 2 seans başlatırsam, her ikisi de 15 milyon kesici uç yapar. Her ikisi de 18 saniyede bitiyor. Daha fazla ölçeklendirebilirim, ancak mevcut test kurulumum iki paralel oturumla% 95 cpu vuruyor, bu yüzden 3 yapmak CPU darboğazına çarpacağım için sonuçları çarpıtır.

Her ikisi de 3 milyon satır ekleyen 2 paralel oturuma başlarsam, ikisi de 39 saniyede biter. 39 saniyede 6 milyon satır.

Tamam, bu hala bizi NETWORK_IO beklemesiyle gösteriyor.

NETWORK_IO beklemeleri, bunları izlemek için genişletilmiş etkinlikler kullanıyor olmanızla eklenir. Benim durumumda insert 36 saniye sürüyor (ortalamada). Genişletilmiş etkinlik yolunu kullanırken (ilk yorumda yukarıdaki bağlantıdan) kayıtlı olan budur:

Wait Type             Wait Count  Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms)
NETWORK_IO            3455        68808                68802                         6
PAGEIOLATCH_SH        3           64                   64                            0
PAGEIOLATCH_UP        12          58                   58                            0
WRITE_COMPLETION      8           15                   15                            0
WRITELOG              3           9                    9                             0
PAGELATCH_UP          2           4                    4                             0
SOS_SCHEDULER_YIELD   32277       1                    0                             1
IO_COMPLETION         8           0                    0                             0
LATCH_SH              3           0                    0                             0
LOGBUFFER             1           0                    0                             0

NETWORK_IO'nun 68 saniyesinin kaydedildiğini görebilirsiniz. Ancak, ekleme döngüsü 36 saniye süren tek iş parçacıklı bir işlem olduğundan, bu olamaz. (Evet, birden çok iş parçacığı kullanılır, ancak işlemler hiçbir zaman paralel değildir, bu nedenle sorgunun toplam süresinden daha fazla bekleme süresi toplayamazsınız)

Ben genişletilmiş olayları kullanmıyorum ama sadece (ben sadece insert eklemek ile) sessiz bir örnekte bekleme istatistikleri DMVs bunu elde:

Wait Type                   Wait Count  Total Wait Time (ms)  Total Resource Wait Time (ms) Signal Resource Wait Time (ms)
SOS_SCHEDULER_YIELD             8873                 0.21                                    0.01                                    0.20
PAGEIOLATCH_UP                  3                    0.02                                    0.02                                    0.00
PREEMPTIVE_OS_AUTHENTICATIONOPS 17                   0.02                                    0.02                                    0.00
PAGEIOLATCH_SH                  1                    0.00                                    0.00                                    0.00

Bu nedenle, genişletilmiş olaylar günlüğünde gördüğünüz NETWORK_IO, ekleme döngünüzle ilgili değildi. (Nocount'ı açmazsanız, büyük eşzamansız ağ IO bekler, +1 Martin olurdu)

Ancak, NETWORK_IO'nun neden genişletilmiş olay izlemesinde gösterildiğini bilmiyorum. Olayların zaman uyumsuz bir dosya hedefine yazıldığından emin olun ASYNC_NETWORK_IO birikir, ancak elbette tüm bunlar filtrelediğimizden farklı bir SPID'de yapılır. Bunu kendim için yeni bir soru olarak sorabilirim)


1
"herhangi bir kaynak darboğazını görmeden bir performans tavanına vuruyorsunuz, çünkü tek oturumda tek bir iş parçacığında işlemenin mümkün olduğu sınıra ulaşmış olmanızdır":% 100 CPU darboğazını (bir çekirdekte) tanımlıyorsunuz. Hiçbir darboğaz yoksa, o zaman sistem olacak başka bir şey oynayan olmalı böylece, daha hızlı.
Remus Rusanu

Cevabınız çok bilgilendirici Edward. Paralellik, zaten üzerinde çalıştığımız sorunumuzun çözümü gibi görünüyor, ancak veritabanı düzenimizde değişiklikler gerektiriyor. Ancak Remus gibi, hala makinenin neden tüm (bir) CPU veya disk kaynaklarını kullanmadığını merak ediyorum.
Djof

9

Genelde bakarak başlamak sys.dm_exec_requestsözellikle de wait_time, wait_typeve wait_resourcesizin INSERT isteği (ler) için. Bu, INSERT'inizi neyin engellediğini net bir şekilde gösterecektir. Sonuçlar kilit çekişmesi, dosya büyüme olayları, günlük sifonu beklemeleri, ayırma çekişmesi (PFS sayfası mandal çekişmesi olarak tezahür eder) vb. Olup olmadığını gösterecektir. Devam etmenizi ve devam etmeden önce Bekler ve Kuyruklarda sorun giderme yöntemini okumanızı önemle rica ediyorum .


3

Test komut dosyasını döngüde BEGIN TRAN / COMMIT ile OP'de bağlı sayfada çalıştırdım. Makinemde ilk kez tamamlanması 1:28 sürdü.

Sonra bu iki komutu döngü dışına taşıdım:

SELECT @Random = ROUND(((@Upper - @Lower -1) * RAND() + @Lower), 0)
SET @InsertDate = DATEADD(dd, @Random, GETDATE())

Bundan sonra 28 saniye içinde tamamlandı.

Ne olduğunu tam olarak bilmiyorum, ama RAND()belki de entropi (daha iyi rasgele sayılar) oluşturmak için kullandıkları algoritmanın bir parçası olarak , kodda bir tür uyku olabilir tahmin ediyorum .

FWIW, SSD'ler, ağır yazma uygulamaları için her zaman en iyi teknoloji değildir. En iyi performans için, DB günlüğünüzün DB verilerinden farklı bir sürücü harfinde olduğundan, günlük dosyasının maksimum boyutuna önceden büyütüldüğünden ve günlüğü asla kesmediğinden emin olun.


RickNZ yazdığınız için teşekkürler. Kodu döngü dışına taşıyarak daha hızlı sonuç alamadım. Gözlemledim ki, birden fazla kez çalıştırırsanız daha hızlı olur, yaşadığınız şey bu olabilir. SSD'lerin gümüş mermi olmadığını biliyorum, ama yine de performansın olabileceği gibi olmadığını hissediyorum.
Djof


0

Sql 2008 için bekleme olayları listesini kontrol ediyorum ve listelenen NETWORK_IO görmüyorum: http://technet.microsoft.com/en-us/library/ms179984(v=sql.100).aspx

NETWORK_IO'nun şimdi ASYNC_NETWORK_IO olarak listelendiğini düşündüm, bu yüzden SQL sürümünüzü tekrar kontrol edip edemeyeceğinizi sormak istedim, çünkü sadece bu bekleme olayının bu sürüm için nasıl / neden göründüğünü merak ediyorum.

Ağ beklemek hiç görünmüyor, evet bu bağımsız bir sunucu üzerinde çalışıyor olsa bile olabilir. Ağ kartlarınızın ayarlarını kontrol ettiniz mi? Bir sorun olup olmadığını merak ediyorum.

Günün sonunda sadece birkaç kaynak tıkanıklığı olabilir: bellek, CPU, disk G / Ç, ağ ve kilitleme. CPU ve I / O'nun sorun olmadığını belirttiniz ve NETWORK_IO için bir bekleme olayınız var, bu yüzden önce bu NIC kartlarına bakmanızı öneririz.


1
NETWORK_IOOP uzun süreli etkinlikleri kullandığından gösterilmektedir. Hiç güncellenmedisys.dm_xe_map_values
Martin Smith

Aynı SQLRockstar'ı düşünüyorum, sadece neler olabilir. Ağ kartlarını tamamen devre dışı bırakmayı denedim. Martin, bazı eski dosyaların hala orada olabileceğine dikkat çekti ve bir şey değiştirip değiştirmediğini görmek için sonuçları yarın güncelleyeceğim.
Şubat'ta Djof

ayrıca, ifadelerin yürütme planlarını görebilseydik de yardımcı olabilir.
SQLRockstar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.