SQL Server 2016 Bozuk Sorgu Planı DB'yi haftada bir kez kilitler


16

Haftada bir kez, son 5 hafta boyunca, günün aynı saatinde (sabahın erken saatlerinde, insanlar kullanmaya başladığında kullanıcı etkinliğine bağlı olabilir), SQL Server 2016 (AWS RDS, yansıtılmış) çok zaman aşımına uğrar sorguları.

GÜNCELLEME İSTATİSTİKLERİ tüm tablolarda her zaman hemen düzeltir.

İlk kez, tüm tablolardaki tüm istatistikleri gecelik (haftalık yerine) güncellemiştim, ancak yine de oldu (güncelleme istatistikleri çalıştıktan yaklaşık 8 saat sonra, ancak çalıştığı her gün değil).

Bu son kez, hangi sorgu / sorgu planının bulabildiğini görmek için Query Store'u etkinleştirdim. Sanırım onu ​​biriyle daraltabildim:

Hatalı sorgu planı

Bu sorguyu bulduktan sonra, bu sık kullanılmayan sorguda eksik olan (ancak sık kullanılan tabloların çoğuna dokunan) önerilen bir dizin ekledim.

Hatalı sorgu planı bir dizin taraması yapıyordu (yalnızca 10 bin satır içeren bir tabloda). Milisaniye cinsinden dönen diğer sorgu planları, aynı taramayı yapardı. En yeni sorgu planı, yeni dizin oluşturduktan sonra sadece arar. Ancak bu endeks olmadan bile, zamanın% 99'u birkaç milisaniye içinde geri dönüyordu, ancak daha sonra haftalık olarak> 40 saniye sürüyordu.

Bu, 2012'den itibaren SQL Server 2016'ya geçtikten sonra olmaya başladı.

DBCC CHECKDB hata döndürmez.

  1. Yeni endeks sorunu düzelterek bir daha kötü planı tekrar seçmeyecek mi?
  2. Şimdi iyi çalışan planı "zorlamalı mıyım?"
  3. Bunun başka bir sorguya / plana gerçekleşmediğinden nasıl emin olabilirim?
  4. Bu daha büyük bir sorunun belirtisi mi?

Az önce eklediğim dizinler:

CREATE NONCLUSTERED INDEX idx_AppointmetnAttendee_AttendeeType
ON [dbo].[AppointmentAttendee] ([UserID],[AttendeeType])

CREATE NONCLUSTERED INDEX [idx_appointment_start] ON [dbo].[Appointment]
(
    [ProjectID] ASC,
    [Start] ASC
)
INCLUDE (   [ID],
    [AllDay],
    [End],
    [Location],
    [Notes],
    [Title],
    [CreatedByID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Tam sorgu metni:

https://pastebin.com/Z5szPBfu (LINQ tarafından oluşturulan, seçilen sütunları optimize edebilirim / yapabilirim, ancak bu sorunla alakasız olmalıdır)


Sadece zaman aşımına uğramayan Önceki planlardaki taramanın, aynı boyutta farklı bir masada olduğunu fark ettim. Randevu: 11931 satır, Randevu Bitiş: 11937 satır.
Profesyonel Sondaj Adı

Yanıtlar:


16

Sorularınızı, sizden istediklerinden farklı bir sırayla cevaplayacağım.

4. Bu daha büyük bir sorunun belirtisi mi?

Yeni kardinalite tahmincisi SQL Server 2016 yılında soruna katkıda edilebilir. SQL Server 2012, eski CE'yi kullanır ve sorununuzu bu sürümde yaşamadınız. Yeni kardinalite tahmincisi verileriniz hakkında farklı varsayımlar yapar ve aynı SQL için farklı sorgu planları oluşturabilir. Sorgunuza ve verilerinize bağlı olarak eski CE ile bazı sorgular için daha iyi performans elde edebilirsiniz. Bu nedenle, veri modelinizin bazı bölümleri yeni CE için en uygun olmayabilir. Sorun değil, ama şimdilik yeni CE üzerinde çalışmanız gerekebilir.

Günlük istatistik güncellemelerinde bile tutarsız sorgu performansı ile ilgilenirim. Dikkat edilmesi gereken önemli bir nokta, tüm tablolarda istatistik toplamanın tüm sorgu planlarını önbellekten etkili bir şekilde sileceğidir, bu nedenle istatistiklerle ilgili bir sorununuz olabilir veya parametre koklamasıyla ilgili olabilir. Veri modeliniz, veri değişim oranı, istatistik güncelleme politikaları, kodunuzu nasıl çağırdığınız vb. Hakkında çok fazla bilgi vermeden bir belirleme yapmak zordur. SQL Server 2016, parametre koklaması için yardımcı olabilecek bazı veritabanı seviyesi ayarları sunar , ancak bu yalnızca tek sorunlu sorgu yerine uygulamanızı etkileyebilir.

Bu davranışa yol açabilecek örnek bir senaryo oluşturacağım. Dedin:

Bazı kullanıcıların 1 izin kaydı olabilir, bazıları 20k'ye kadar.

Tüm sorgu planlarını silen tüm tablolarda istatistikleri topladığınızı varsayalım. Yukarıda belirtilen faktörlere bağlı olarak, günün ilk sorgusu sadece 1 izin kaydı olan bir kullanıcıya karşı ise, SQL Server 1 kaydı olan kullanıcılar için iyi çalışan ancak 20k kaydı olan kullanıcılarla çok iyi çalışan bir planı önbelleğe alabilir. Günün ilk sorgusu 20 bin kayıtlı bir kullanıcıya karşı ise, 20 bin kayıt için iyi bir plan alabilirsiniz. Kod 1 kaydı olan bir kullanıcıya karşı çalıştırıldığında, en uygun sorgu olmayabilir ancak ms olarak bitebilir. Gerçekten parametre koklama gibi geliyor. Sorunu neden her zaman görmediğinizi veya neden bazen görünmesinin saatler sürdüğünü açıklar.

1. Yeni endeks sorunu düzelterek bir daha kötü planı bir daha seçmeyecek mi?

Eklediğiniz dizinlerden birinin sorunu önleyeceğini düşünüyorum, çünkü gerekli verilere dizin aracılığıyla erişmek, özellikle tarama erken sonlandırılamadığında tabloya göre kümelenmiş bir dizin taraması yapmaktan daha ucuz olacaktır. Sorgu planının kötü kısmını yakınlaştıralım:

hatalı sorgu planı

SQL Server, birleşimden [Permission]ve öğelerinden yalnızca bir satırın döndürüleceğini tahmin eder [Project]. Dış girişteki her satır için kümelenmiş bir dizin taraması yapar [Appointment]. Tüm satırlar bu tablodan taranacaktır, ancak yalnızca filtrelemeyle eşleşen satırlar [Start]birleştirme operatörüne döndürülecektir. Birleştirme operatörü içinde sonuçlar daha da azaltılır.

Birleştirmenin dış girişine gerçekten yalnızca bir satır gönderilmişse, yukarıda açıklanan sorgu planı iyi olabilir. Ancak, birleşimden gelen kardinalite tahmini yanlışsa ve diyelim ki 1000 satır alırsak, SQL Server 1000 kümelenmiş dizin taraması yapar [Appointment]. Sorgu planının performansı tahmin sorunlarına çok duyarlıdır.

Bir daha asla bu sorgu planını almanın en doğrudan yolu [Appointment]tabloya karşı bir kaplama dizini oluşturmak olacaktır . Bir dizin gibi bir şey [ProjectId]ve [Start]bunu yapmak gerekir. Bu [idx_appointment_start], sorunu çözmek için oluşturduğunuz dizindir. Sorgu planını alarak gelen SQL sunucusu vazgeçirmek için bir başka yolu üzerinden birleştirmek gelen önem düzeyi tahmini düzeltmek için olduğunu [Permission]ve [Project]. Kodun değiştirilmesi, istatistiklerin güncellenmesi, eski CE'nin kullanılması, çok sütunlu istatistiklerin oluşturulması, SQL Server'a RECOMPILEipucu gibi yerel değişkenler hakkında daha fazla bilgi verilmesi veya bu satırların geçici bir tablo haline getirilmesi için tipik yollar . MS düzeyinde yanıt süresine ihtiyaç duyduğunuzda veya bir ORM aracılığıyla kod yazmanız gerektiğinde bu tekniklerin çoğu iyi bir yaklaşım değildir.

Oluşturduğunuz dizin [AppointmentAttendee], sorunu ele almanın doğrudan bir yolu değildir. Ancak, dizinde çok sütunlu istatistikler alırsınız ve bu istatistikler bozuk sorgu planını engelleyebilir. Dizin, kötü sorgu planını da engelleyebilecek verilere erişmek için daha etkili bir yol sağlayabilir, ancak bunun yalnızca dizinle tekrar olmayacağının herhangi bir garantisi olduğunu düşünmüyorum [AppointmentAttendee].

3. Bunun başka bir sorguya / plana gerçekleşmediğinden nasıl emin olabilirim?

Bu soruyu neden sorduğunuzu anlıyorum ama bu çok geniş bir soru. Tek tavsiyem, sorgu planı kararsızlığının temel nedenini daha iyi anlamaya çalışmak, iş yükünüz için doğru dizinlere sahip olduğunuzu doğrulamak ve iş yükünüzü dikkatle test etmek ve izlemek. Microsoft, SQL Server 2016'daki yeni CE'nin neden olduğu sorgu planı gerilemeleriyle nasıl başa çıkılacağı konusunda bazı genel önerilere sahiptir :

Sorgu işlemcisini kodun en son sürümüne yükseltmek için önerilen iş akışı:

  1. Veritabanı uyumluluk düzeyini değiştirmeden bir veritabanını SQL Server 2016'ya yükseltin (önceki düzeyde tutun)

  2. Veritabanında sorgu deposunu etkinleştirin. Sorgu deposunu etkinleştirme ve kullanma hakkında daha fazla bilgi için, bkz. Sorgu Deposunu Kullanarak Performansı İzleme.

  3. İş yükünün temsili verilerini toplamak için yeterli süre bekleyin.

  4. Veritabanının uyumluluk düzeyini 130 olarak değiştirin

  5. SQL Server Management Studio'yu kullanarak, uyumluluk düzeyi değişikliğinden sonra belirli sorgularda performans gerilemeleri olup olmadığını değerlendirin

  6. Regresyonların olduğu durumlarda, sorgu deposunda önceki planı zorlayın.

  7. Zorlamayan sorgu planları varsa veya performans hala yetersizse, uyumluluk düzeyini önceki ayara getirmeyi ve ardından Microsoft Müşteri Desteği'ni kullanmayı düşünün.

SQL Server 2012'ye geçmeniz ve baştan başlamanız gerektiğini söylemiyorum, ancak açıklanan genel teknik sizin için yararlı olabilir.

2. Şimdi iyi çalışan planı "zorlamalı mıyım?"

Tamamen size kalmış. Tüm olası giriş parametreleri için iyi çalışan bir sorgu planınız olduğuna inanıyorsanız, sorgu deposunun işlevselliği ile rahatınız ve bir sorgu planını zorlamakla birlikte gelen gönül rahatlığını istiyorsanız, bunun için gidin. Gerileme olan sorgu planlarını zorlamak, Microsoft'un SQL Server 2016'ya yükseltme ilkesini önermesinin bir parçasıdır.

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.