Veritabanındaki tüm tabloların sıkıştırılmamış boyutunu bulma


12

Dynamics AX'te, tabloların belleğe yüklenecek ve önbelleğe alınacak şekilde yapılandırılabileceği bir önbellekleme mekanizması vardır. Bu önbellek, bellek sorunlarını önlemek için belirli bir KB miktarı ile sınırlıdır. Bahsettiğim ayar denir entiretablecacheve tek bir kayıt istendiğinde tüm tabloyu belleğe yükler.

Yakın zamana kadar, tablo boyutunun bu sınırın üzerinde olup olmadığını görmek için bu ayara sahip tabloların boyutunu doğrulamak için bazı komut dosyalarına güveniyorduk.

Ancak şimdi sıkıştırma devreye giriyor ve sp_spaceused veya sys.allocation_units gibi şeyler sıkıştırılmış veriler tarafından kullanılan alanı rapor ediyor gibi görünüyor.

Açıkçası, uygulama sunucusu sıkıştırılmamış verilerle çalışmaktadır, bu nedenle SQL Server'daki diskteki veri boyutu önemsizdir. Sıkıştırılmamış verilerin sahip olacağı gerçek boyuta ihtiyacım var.

Ben sp_estimate_data_compression_savings biliyorum ama adından da anlaşılacağı gibi, bu sadece bir tahmindir.
Mümkün olduğunca doğru boyuta sahip olmayı tercih ederim.

Düşünebildiğim tek yol, sıkıştırılmış tablolarla aynı yapıya sahip sıkıştırılmamış tablolar oluşturmak, bu gölge tabloya sıkıştırılmış verileri eklemek ve daha sonra bu gölge tablonun boyutunu kontrol etmek için bazı karmaşık dinamik SQL'di.
Söylemeye gerek yok, bu biraz sıkıcı ve birkaç yüz GB'lık bir veritabanında çalıştırmak biraz zaman alıyor.

Powershell bir seçenek olabilir, ama ben select *sadece önbellek sel ve muhtemelen çok uzun zaman alacağı gibi komut dosyası boyutunu kontrol etmek için bir tablo gerçekleştirmek için tüm tablolar üzerinde tekrarlamak istemem.

Kısacası, her tablo için boyutu bir kez sıkıştırılmayacağı ve mümkün ise, uygulamaya sunulan denklemin dışında parçalanacağı için bir yol almam gerekiyor. Farklı yaklaşımlara açıkım, T-SQL tercih ediliyor, ancak Powershell veya diğer yaratıcı yaklaşımlara karşı değilim.

Uygulamadaki arabelleğin verilerin boyutu olduğunu varsayalım. Bigint her zaman bigint büyüklüğündedir ve karakter veri türü karakter başına 2 bayttır (unicode). BLOB verileri de verilerin boyutunu alır, bir enum temel olarak int ve sayısal veriler sayısaldır (38,12), datetime datetime boyutudur. Ayrıca, hiçbir NULLdeğer yoktur , bunlar boş bir dize 1900-01-01veya sıfır olarak saklanır .

Bunun nasıl uygulandığına dair herhangi bir belge yoktur, ancak varsayımlar bazı testlere ve PFE'ler ve destek ekibi tarafından kullanılan komut dosyalarına dayanmaktadır (kontrol uygulamada oluşturulduğundan ve uygulama söyleyemediği için sıkıştırmayı da göz ardı eder) alttaki veriler sıkıştırılmışsa) bu da tablo boyutlarını kontrol eder. Örneğin bu bağlantı şunları belirtir:

Büyük tablolar için WholeTable önbellekleri kullanmaktan kaçının (AX 2009'da 128 KB veya 16 sayfadan fazla, AX 2012'de 'tüm tablo önbellek boyutu' uygulama ayarı [varsayılan: 32KB veya 4 sayfa]) - bunun yerine önbelleğe kaydetmek için taşıyın.


3
Bu hacky, ama belki de sıkıştırma devre dışı bırakılmış geri yüklenen bir kopya en kesin olurdu. Daha sonra, bir TOP 1 DBA gibi görünmenizi sağlayan geri yüklemeleri de test ediyorsunuz.
Erik Darling

Bunun en iyi seçeneğin olduğuna inan. Matematiği denemek ve yapmak için yollar olabilir. Tanımlanmış sütun veri türlerine ve uzunluklarına göre kaç satır çarpılır ve ardından dizinlere eklenir, vb. Ve kim TOP 1 DBA olmak istemez ki?
Mike Walsh

Tüm sütun için TOPLA (veri uzunluğu ()) sıkıştırılmamış veri boyutu olsun?
Tapakah Ua

@sp_BlitzErik Bu bir yorum yerine bir cevap olabilir.
Tom V - topanswers.xyz'yi deneyin

Yanıtlar:


7

Sıkıştırılmamış verilerin sahip olacağı gerçek boyuta ihtiyacım var.
...
mümkün olduğunca doğru boyuta sahip olmayı tercih ederim.

Bu bilgi arzusu kesinlikle anlaşılabilir olsa da, bu bilgiyi, özellikle "mümkün olduğunca doğru" bağlamında elde etmek, hatalı varsayımlar nedeniyle herkesin beklediğinden daha zordur. İster soruda belirtilen sıkıştırılmamış gölge tablosu fikrini ister DB'yi geri yükleme ve kontrol etmek için orada sıkıştırmayı açma hakkındaki bir yorumda @ sp_BlitzErik'in önerisi olsun, sıkıştırılmamış tablonun boyutunun == hafızadaki söz konusu verilerin boyutu olduğu varsayılmamalıdır. uygulama sunucusunda:

  1. Are tüm tablodaki satırlar önbelleğe alınmasını? Yoksa sadece bir menzil içinde mi? Buradaki varsayım, her şeyin olduğu ve bu doğru olabilir, ancak en azından bunun böyle olmayabileceğini düşündüm (belgelerin aksini belirtmedikçe, ancak bu zaten küçük bir nokta, sadece istemedim) bahsedilmeyecektir).

    Soru şu şekilde güncellendi: evet, tüm satırlar önbelleğe alınıyor.

  2. Yapı yükü

    1. DB tarafında: DB tarafında
      sayfa ve satır ek yükü: Bir sayfaya kaç satır sığdığı tahminleri atabilecek birçok faktör tarafından belirlenir. FILLFACTOR100 (veya 0) 'dan biriyle bile, tüm satır için yeterli olmadığı için sayfada hala kullanılmayan bir alan olması muhtemeldir. Ve bu sayfa başlığına ek olarak. Ayrıca, herhangi bir Anlık Görüntü Yalıtımı işlevi etkinleştirilirse, sürüm numarası tarafından alınan satır başına fazladan 13 bayt olacağına ve bu da tahminleri atacağına inanıyorum. Satırın gerçek boyutu (NULL bitmap, değişken uzunluklu sütunlar, vb.) İle ilgili başka minutia da vardır, ancak şimdiye kadar bahsedilen öğeler tek başına noktaya gelmelidir.
    2. Uygulama sunucusu tarafında:
      Önbelleğe alınan sonuçları depolamak için ne tür bir koleksiyon kullanılıyor? Bu bir .NET uygulaması olduğunu varsayalım, bu yüzden bir DataTable? Genel bir liste? SortedDictionary? Her koleksiyon türünün farklı bir kulak misafiri vardır. Ben özellikle DB tarafında Sayfa ve Satır ek yükleri yansıtmak için seçeneklerin hiçbirini beklemem (özellikle küçük bir satır önemli miktarda yeterli olmayabilir emin olabilirsiniz, ama farklılıklar arıyor değilim yüzlerce bayt veya sadece birkaç kB).
  3. Veri tipleri
    1. DB tarafında:
      CHAR/ VARCHARdata karakter başına 1 baytta saklanır (şimdilik çift baytlık karakterler yok sayılır). XMLmetin temsilinin gerektirdiği kadar yer kaplamayacak şekilde optimize edilmiştir. Bu veri türü, bir öğe ve öznitelik adları sözlüğü oluşturur ve belgedeki gerçek referansları ilgili kimlikleriyle değiştirir (aslında çok güzel). Aksi halde, dize değerleri tüm UTF-16 ( "karakteri" başına 2 veya 4 bayt) gibi, vardır NCHAR/ ' NVARCHAR. DATETIME26 ile 8 bayt arasındadır. DECIMAL5 ila 17 bayt arasındadır (hassasiyete bağlı olarak).
    2. Uygulama sunucusu tarafında:
      Dizeler (yine .NET varsayıldığında) her zaman UTF-16'dır. Ne gibi 8 bit dizeler için herhangi bir optimizasyon yoktur VARCHAR. ANCAK, dizeleri de birçok kez başvurulabilir paylaşılan bir kopya olan "interned" olabilir (ama bu koleksiyonları dizelerde işe ya da öyleyse, tüm koleksiyon türleri için çalışıyorsa bilmiyorum). XMLbellekte aynı şekilde saklanabilir ya da saklanmayabilir (bunu aramam gerekecek). DateTimeher zaman 8 bayttır (T-SQL DATETIMEgibi DATE, ancak , gibi değil TIMEveya DATETIME2). Decimalher zaman 16 bayttır .

Tüm bunları söylemek için: DB tarafında , uygulama sunucusu tarafında oldukça doğru bellek ayak izi boyutu elde etmek için yapabileceğiniz hemen hemen hiçbir şey yoktur . Belirli bir tabloyla yüklendikten sonra uygulama sunucusunun kendisini sorgulamanın bir yolunu bulmanız gerekir, bu yüzden ne kadar büyük olduğunu bilin. Ve bir hata ayıklayıcı dolu bir koleksiyonun çalışma zamanı boyutunu görmenize izin verecek emin değilim. Değilse, yakınlaşmanın tek yolu, bir tablonun tüm satırlarından geçmek ve her sütunu uygun .NET boyutuyla (örneğin, INT= * 4, VARCHAR= DATALENGTH() * 2, NVARCHAR= DATALENGTH(), XML= 🙃, vb.) Çarpmaktır, ancak bu yine de soruyu bırakır ve eklentinin her öğesinin ek yükü.

Sorudaki bazı yeni tanımlar göz önüne alındığında, muhtemelen oldukça yakınlaşmak için aşağıdaki sorguyu yapabilir. Tablonun sıkıştırılıp sıkıştırılmaması önemli değildir, ancak tüm satırları taramanın Üretimde uygun olup olmadığını belirlemek her kişiye bağlıdır (belki geri yükleme veya yoğun olmayan saatler sırasında):

SELECT
   SUM( DATALENGTH([NVarcharColumn_1]) + DATALENGTH([NVarcharColumn_N]) ) + 
   SUM( (DATALENGTH([VarcharColumn_1]) + DATALENGTH([VarcharColumn_N])) * 2 ) + 
   SUM(4 * [number_of_INT_columns]) +
   SUM(8 * [number_of_BIGINT_and_DATETIME_columns]) +
   SUM(16 * [number_of_DECIMAL/NUMERIC_and_UNIQUEIDENTIFIER_columns]) +
   etc..
FROM [SchemaName].[TableName] WITH (NOLOCK) -- assuming no Snapshot Isolation

Ancak unutmayın, bu toplama veya toplama elemanı ek yükünü hesaba katmaz. Ve bu değeri bir hata ayıklayıcı olmadan (veya muhtemelen ILSpy gibi bir şey olmadan alabilir miyiz emin değilim, ama yerel yasalara bağlı olarak EULA'yı ihlal edebileceği için bunu tavsiye etmiyorum ).


Uygulamaya sunulduğu için arabellek boyutundan emin olmak için koddaki kontrolleri uyguladık.
Tom V - topanswers.xyz'yi deneyin

6

Sorunuzdan, maksimum önbellek boyutuna sahip olduğunuz Sve önbelleğe bu boyutu aşan tablolar yüklemek istemediğiniz anlaşılıyor. Bu doğruysa, her tablonun tam boyutunu bilmenize gerek yoktur. Bir tablonun maksimum önbellek boyutundan daha büyük veya daha küçük olup olmadığını bilmeniz gerekir S. Bu, tablolarınızın sütun tanımlarına ve satır sayılarına bağlı olarak çok daha kolay bir sorundur.

Solomon Rutzky'nin sıkıştırılmamış verilere bakmanın bir yol olmadığı ve önbellekteki bir tablonun gerçek boyutu için iyi bir yaklaşım bulmak zor olabileceğine dair büyük cevabına katılıyorum. Ancak, soru çerçevesinde çalışacağım ve statik veri türleri için sütun tanımlarına ve dinamik sütunlarınızın gerçek uzunluğuna göre yeterince yakın bir formül geliştirebileceğinizi varsayacağım.

Veri türlerinin önbellek boyutuyla eşleştirilmesine sahipseniz, bazı tabloları içindeki verilere bakmadan değerlendirebilmeniz gerekir:

  1. Bir tabloda yalnızca statik veri türleri varsa (dizeler veya bloblar yoksa) sys.partitions, sütun tanımlarını kullanarak tablonun boyutunu bakarak hesaplayabilir ve satır sayısını hesaplayabilirsiniz.
  2. Çok sayıda satır içeren bir tabloda yeterli statik veri türü sütunu varsa, verilerine bakmadan tabloyu çok büyük olarak kaldırabilirsiniz. Örneğin, 10 milyon satır ve 5 BIGINTsütuna sahip bir tablo , bu verilerin boyutunu 10000000 * (8 + 8 + 8 + 8 + 8) = önbellek boyut sınırınızdan daha büyük olabilecek 400 M bayt boyutunda olabilir S. Bir dizi dize sütununun olması da önemli değil.
  3. Birkaç satır içeren bir tablo yeterince küçükse, her bir dinamik veri türünün mümkün olan maksimum boyuta sahip olduğunu varsayarak sınırın altında olduğunu onaylayabilirsiniz. Örneğin, BIGINTsütunu ve NVARCHAR(20)sütunu olan 100 satırlık bir tablo 100 * (8 + 2 * 20) = 4800 baytı aşamaz.
  4. Bir tablonun SQL Server'da sıkıştırılmış bir boyutu varsa S, bunun bazı faktörlerden daha büyük olması, önbelleğe sığmasının son derece düşük olduğu doğru olabilir. Böyle bir değerin var olup olmadığını anlamak için test yapmanız gerekir.
  5. Tüm dinamik sütunların üzerinde istatistik olduğu için şanslı olabilirsiniz. İstatistikler, ortalama uzunluk hakkında bilgi içerir ve bu, amaçlarınız için yeterince doğru olabilir.

Yukarıdaki kriterlere uymayan tabloların verilerini sorgulamanız gerekebilir. Bunun performans üzerindeki etkisini en aza indirmek için kullanabileceğiniz bazı püf noktaları vardır. Burada iki rakip önceliğe sahip olduğunuzu söyleyebilirim: doğruluğa değer veriyorsunuz ancak veritabanınızdaki tüm verileri taramak istemiyorsunuz. Hesaplamalarınıza bir tür tampon eklemek mümkün olabilir. Maksimum önbellek boyutunun biraz altında bir tabloyu hariç tutmanın Sveya maksimum önbellek boyutunun biraz üzerinde bir tablo eklemenin daha kabul edilebilir olup olmadığını bilmiyorum .

Tablo verilerine daha hızlı bakan sorguları daha hızlı hale getirmek için bazı fikirler:

  1. Büyük tablolar için TABLESAMPLE, örnek boyutunuz yeterince büyük olduğu sürece kullanabilirsiniz .
  2. Kümelenmiş anahtara sahip büyük tablolar için, bunları kümelenmiş anahtardaki gruplar halinde işlemek yararlı olabilir. Maalesef SUM()bu toplamın değerine dayanarak erken ayrılan bir hesaplamanın bir yolunu bilmiyorum . Sadece bu işi gördüm ROW_NUMBER(). Ancak tablonun ilk% 10'unu tarayabilir, hesaplanan veri boyutunu kaydedebilir, sonraki% 10'u tarayabilir vb. Önbellek için çok büyük olan tablolar için, bu yaklaşımdan erken çıkarak önemli miktarda çalışma kaydedebilirsiniz.
  3. Bazı tablolar için, tüm dinamik sütunlarda kapsayan dizinlere sahip olacak kadar şanslı olabilirsiniz. Satır boyutuna veya her bir dizini tek seferde taramaya bağlı diğer faktörlere bağlı olarak tablo taramasından daha hızlı olabilir. Tek bir sütunda bir dizin okuduktan sonra tablo boyutu çok büyükse bu işlemden erken çıkabilirsiniz.
  4. Dinamik sütunlarınızın ortalama uzunlukları zaman içinde çok fazla değişmiyor olabilir. Hesapladığınız ortalama uzunlukları korumak ve bu değerleri hesaplamalarınızda bir süre kullanmak pratik olabilir. Bu değerleri tablolardaki DML etkinliğine veya başka bir metriğe göre sıfırlayabilirsiniz.
  5. Bir algoritma geliştirmek için tüm tablolar üzerinde testler yapmak mümkünse, verilerdeki desenlerden yararlanabilirsiniz. Örneğin, en küçükten başlayarak tabloları işlerseniz, önbellek için çok büyük bir satırda 10 (bu sayıyı oluşturdum) tabloları işledikten sonra, daha büyük tabloların önbelleği. Önbelleğe sığabilecek birkaç tabloyu hariç tutmanız uygunsa bu kabul edilebilir.

Bu cevaba herhangi bir SQL kodu eklemediğimi fark ettim. Burada tartıştığım fikirlerden herhangi biri için demo kodu yazmanın faydalı olup olmadığını bana bildirin.


2
Bu tür tabloları hariç tutma yaklaşımını düşünmemiştim, yaklaşımı seviyorum
Tom V - topanswers.xyz'i deneyin
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.