LOB_DATA, yavaş tablo taramaları ve bazı G / Ç soruları


19

Ben sütunlardan biri ~ 15 kilobayt olmak ortalama bir XML girişi boyutu ile bir XML veri olan oldukça büyük bir tablo var. Diğer tüm sütunlar normal ints, bigints, GUID'ler vb. Bazı somut sayılara sahip olmak için tablonun bir milyon satırı olduğunu ve ~ 15 GB boyutunda olduğunu varsayalım.

Ne fark ettim, tüm sütunları seçmek istersem bu tablodan veri seçmek gerçekten yavaş. Ben yaparken

SELECT TOP 1000 * FROM TABLE

verileri diskten okumak yaklaşık 20-25 saniye sürer - sonuçta herhangi bir sipariş vermeme rağmen. Ben soğuk önbellek (yani sonra DBCC DROPCLEANBUFFERS) ile sorgu çalıştırın . İşte IO istatistik sonuçları:

Tarama sayısı 1, mantıksal okumalar 364, fiziksel okumalar 24, okuma öncesi okumalar 7191, lob mantıksal okumalar 7924, lob fiziksel okumalar 1690, lob okuma öncesi okumalar 3968.

~ 15 MB veri toplar. Yürütme planı beklediğim gibi Kümelenmiş Dizin Tarama'yı gösteriyor.

Sorgularımın yanında diskte herhangi bir GÇ yok; Ayrıca kümelenmiş dizin parçalanma% 0 yakın olduğunu kontrol ettim. Bu bir tüketici sınıfı SATA sürücüsüdür, ancak SQL Server'ın ~ 100-150 MB / dak.

XML alanının varlığı, tablo verilerinin çoğunun LOB_DATA sayfalarında bulunmasına neden olur (aslında tablo sayfalarının ~% 90'ı LOB_DATA'dır).

Sanırım sorum şu: LOB_DATA sayfalarının yalnızca boyutlarından dolayı yavaş taramalara neden olabileceğini düşünmüyorum, aynı zamanda tabloda çok fazla LOB_DATA sayfası olduğunda SQL Server kümelenmiş dizini etkili bir şekilde tarayamadığı için mi?

Daha da geniş - böyle bir tablo yapısına / veri modeline sahip olmak makul kabul ediliyor mu? Filestream kullanma önerileri genellikle daha büyük alan boyutlarını belirtir, bu yüzden o rotaya gerçekten gitmek istemiyorum. Bu senaryo hakkında gerçekten iyi bir bilgi bulamadım.

XML sıkıştırmayı düşünüyorum, ancak istemcide veya SQLCLR ile yapılması gerekiyor ve sistemde uygulamak için biraz çalışma gerektiriyor.

Sıkıştırma denedim ve XML'ler aşırı yedek olduğundan, (ac # app) XML 20KB ~ 2.5KB sıkıştırmak ve LOB veri sayfalarının kullanımını önleyerek VARBINARY sütununda saklayabilirsiniz. Bu, testlerimde 20x SEÇ seçiyor.


Alex: Cevabımla ilgili tartışmayı görüp görmediğinizden emin değilim (bağlantı cevabımın altındaki bir yorumda yer alıyor), ancak senaryonuzu yeniden üretmeye yaklaşabildim. Açıklamanızla eşleşen bir tablo eşleştirdim (bilgi sahibi olduğum kadarıyla) ve çok benzer G / Ç istatistikleri aldım. Dışında, "LOB Fiziksel Okumalar" asla yakın değildi. Bu yüzden XML'i güncellediğinizi (ancak diğer sütunları değil) ve / veya veri dosyalarınızda çok fazla fiziksel parçalanma olup olmadığını merak ediyordum. Yine de tablonuzun DDL'sini ve her veri dosyası için otomatik büyüme ayarınızı almayı umursamıyorum ve veri dosyalarınızı küçültüyor musunuz?
Solomon Rutzky

Her şeyden önce - ayrıntılı cevap için çok teşekkürler, zaman eksikliği nedeniyle o zaman tartışmaya katılamadım. Şimdi bundan bahsettiğinize göre (soru sorulduğunda bunu düşünmedim) - XML ​​alanı oluşturulduktan sonra birkaç kez güncellenir ve küçük oluşturulur. Bu yüzden başlangıçta satırda saklandığından şüphelenirim ve bazı güncellemelerden sonra bir LOB sayfa yapısına taşınır ve daha sonra bazı güncellemeler alır.
Alexander Shelemin

(Devam) Soruyu sormadan önce dosyaların fiziksel parçalanmasını kontrol ettim ve yerleşik Windows aracı bunun iyi olduğunu düşündü, bu yüzden daha fazla bakmadım. Otomatik büyüme varsayılan, 1 MB inanıyorum ve veri dosyaları küçültülmüş değil.
Alexander Shelemin

İlk 1000'i seç * benim özel durumumda önemlidir. Bunun kötü bir uygulama olduğunu kesinlikle anlıyorum, ancak bazı uygulama tasarımı kararlarının uzun bir süre yürürlüğe girdikten sonra değiştirilmesi gerçekten zor. Select *, temel olarak uygulamamızdaki farklı bileşenler arasında veritabanları arası bir çoğaltma stratejisi olarak kullanılır. Bunun artıları var, örneğin yerleşik çoğaltma teknikleri ile zor olacak şekilde veri / şema ile çok fazla keyfi manipülasyon yapabiliriz, ancak sorunları ile birlikte gelir.
Alexander Shelemin

SELECT *XML verilerine ihtiyacınız varsa Alex, sorun değil. Bu yalnızca XML verilerini istemiyorsanız bir sorundur, bu durumda kullanmadığınız verileri geri almak için sorguyu neden yavaşlattınız? LOB sayfalarındaki parçalanmanın doğru bir şekilde raporlanıp raporlanmadığını merak eden XML güncellemelerini sordum. Bu yüzden cevabımda kümelenmiş dizinin parçalanmadığını tam olarak nasıl belirlediniz? Koştuğun komutu verebilir misin? Ve Kümelenmiş Endeks'te tam bir İYİLEŞTİRME yaptınız mı? (devam ediyor)
Solomon Rutzky

Yanıtlar:


11

XML alanının varlığı, tablo verilerinin çoğunun LOB_DATA sayfalarında bulunmasına neden olur (aslında tablo sayfalarının ~% 90'ı LOB_DATA'dır).

Yalnızca XML sütununun tabloda olması bu etkiye sahip değildir. Bu XML varlığı verilerine , belirli koşullar altında , bir satırın verilerinin bir kısmının LOB_DATA sayfalarında, satır kapalı saklanmasına neden olur. Ve biri (veya belki de birkaç ;-) duh olduğunu iddia edebilirken, XMLsütun gerçekten XML verilerinin olacağını ima eder, ancak XML verilerinin satır dışında depolanması gerektiği garanti edilmez: satır hemen hemen doldurulmadıkça XML verileri olmasının dışında, küçük belgeler (8000 bayta kadar) sıraya sığabilir ve hiçbir zaman LOB_DATA sayfasına gitmeyebilir.

sayfaların boyutu nedeniyle değil, aynı zamanda tabloda çok sayıda LOB_DATA sayfa olduğunda SQL Server kümelenmiş dizini etkili bir şekilde tarayamıyor çünkü LOB_DATA sayfalarının yavaş taramalara neden olabileceğini düşünerek doğru mu?

Tarama, tüm satırlara bakmayı ifade eder. Tabii ki, bir veri sayfası okunduğunda, sütunların bir alt kümesini seçmiş olsanız bile tüm satır içi veriler okunur. LOB verileriyle fark, o sütunu seçmezseniz, satır dışı verilerin okunmayacağıdır. Bu nedenle, SQL Server'ın bu Kümelenmiş Dizini ne kadar verimli bir şekilde tarayabileceği hakkında bir sonuç çıkarmak gerçekten doğru değildir, çünkü tam olarak test etmediniz (veya yarısını test ettiniz). XML sütununu içeren tüm sütunları seçtiniz ve belirttiğiniz gibi, verilerin çoğunun bulunduğu yer burasıdır.

Bu nedenle, SELECT TOP 1000 *testin yalnızca arka arkaya bir dizi 8k veri sayfasını okumadığını, bunun yerine her satırdaki diğer konumlara atladığını zaten biliyoruz . Bu LOB verilerinin tam yapısı, ne kadar büyük olduğuna bağlı olarak değişebilir. Burada gösterilen araştırmaya dayanarak ( Varchar, Varbinary, vb. Gibi (MAX) Tipler için LOB İşaretçisinin Boyutu Nedir? ), İki tip off-line LOB tahsisi vardır:

  1. Satır İçi Kök - 8001 ve 40.000 (gerçekten 42.000) bayt arasındaki veriler için, alan izin verirse, doğrudan LOB sayfalarına yönlendiren 1 ila 5 işaretçi (24 - 72 bayt) olacaktır.
  2. TEXT_TREE - 42.000 baytın üzerindeki veriler için veya 1 ila 5 işaretçi sıraya sığmazsa, LOB sayfalarına işaretçiler listesinin başlangıç ​​sayfasına yalnızca 24 baytlık bir işaretçi (ör. text_tree "sayfası).

Bu iki durumlardan biri her zaman oluştuğu almak 8000 bayt üzerinde ya da sadece içinde satır uymayan LOB veri. PasteBin.com ( LOB tahsislerini ve okumalarını test etmek için T-SQL komut dosyası) bir test komut dosyası ( LOB tahsislerinin 3 tipini (verilerin boyutuna bağlı olarak) ve bunların her birinin mantıksal ve fiziksel okumalar. Sizin durumunuzda, XML verileri gerçekten satır başına 42.000 bayttan azsa, hiçbiri (veya çok azı) en az verimli TEXT_TREE yapısında olmamalıdır.

SQL Server'ın bu Kümelenmiş Dizini ne kadar hızlı tarayabileceğini test etmek istiyorsanız, bunu yapın SELECT TOP 1000ancak bu XML sütununu içermeyen bir veya daha fazla sütun belirtin . Bu sonuçlarınızı nasıl etkiler? Biraz daha hızlı olmalı.

böyle bir tablo yapısına / veri modeline sahip olmak makul kabul edilir mi?

Gerçek tablo yapısının ve veri modelinin eksik bir tanımına sahip olduğumuz göz önüne alındığında, bu eksik detayların ne olduğuna bağlı olarak herhangi bir cevap optimal olmayabilir. Bunu göz önünde bulundurarak, tablo yapınız veya veri deseniniz hakkında açıkça mantıksız bir şey olmadığını söyleyebilirim.

(Ac # app) XML 20KB ~ 2.5KB sıkıştırabilir ve LOB veri sayfalarının kullanımını önleyerek VARBINARY sütununda saklayabilirsiniz. Bu, testlerimde 20x SEÇ seçiyor.

Bu, tüm sütunları ve hatta yalnızca XML verilerini (şimdi VARBINARYiçeri) seçmeyi daha hızlı hale getirdi, ancak aslında "XML" verilerini seçmeyen sorguları incitiyor. Diğer sütunlarda yaklaşık 50 baytınız varsa ve FILLFACTOR100'lük bir değeriniz varsa , o zaman:

  • Sıkıştırma Yok: 15k XMLveri, 2 Satır Kökü için 2 işaretçi gerektiren 2 LOB_DATA sayfası gerektirmelidir. İlk işaretçi 24 bayt ve ikincisi 12'dir ve XML verileri için satırda depolanan toplam 36 bayt için. Toplam satır boyutu 86 bayttır ve bu satırların yaklaşık 93'ünü 8060 baytlık bir veri sayfasına sığdırabilirsiniz. Bu nedenle, 1 milyon satır 10.753 veri sayfası gerektirir.

  • Özel Sıkıştırma: 2,5 bin VARBINARYveri sıraya sığar. Toplam satır boyutu 2610 (2,5 * 1024 = 2560) bayttır ve bu satırlardan yalnızca 3 tanesini 8060 baytlık bir veri sayfasına sığdırabilirsiniz. Bu nedenle, 1 milyon satır 333.334 veri sayfası gerektirir.

Ergo, özel sıkıştırma uygulayarak Kümelenmiş Dizin için veri sayfalarında 30 kat artış sağlar . Yani, Kümelenmiş Dizin taraması kullanan tüm sorguların okunması gereken yaklaşık 322.500 veri sayfası daha var . Bu tür bir sıkıştırma yapmanın ek sonuçları için lütfen aşağıdaki ayrıntılı bölüme bakın.

Ben performans dayalı herhangi bir yeniden düzenleme yapmaya karşı dikkat ediyorum SELECT TOP 1000 *. Bu, uygulamanın bile yayınlayacağı bir sorgu değildir ve potansiyel olarak gereksiz optimizasyon (lar) için tek temel olarak kullanılmamalıdır.

Denemek için daha ayrıntılı bilgi ve daha fazla test için lütfen aşağıdaki bölüme bakın.


Bu soruya kesin bir cevap verilemez, ancak en azından bizi tam konuyu (ideal olarak kanıtlara dayanarak) bulmaya daha da yakınlaştırmaya yardımcı olmak için biraz ilerleme kaydedebilir ve ek araştırma önerebiliriz.

Ne biliyoruz:

  1. Tabloda yaklaşık 1 milyon satır var
  2. Tablo boyutu yaklaşık 15 GB
  3. Tablo birini içeren XMLsütunu ve türleri çeşitli diğer sütunları: INT, BIGINT, UNIQUEIDENTIFIER, "vb"
  4. XML"boyut" sütunu ortalama olarak yaklaşık 15k
  5. Çalıştırdıktan sonra DBCC DROPCLEANBUFFERS, aşağıdaki sorgunun tamamlanması 20-25 saniye sürer:SELECT TOP 1000 * FROM TABLE
  6. Kümelenmiş Dizin taranıyor
  7. Kümelenmiş Dizindeki Parçalanma% 0'a yakın

Bildiğimizi düşündüğümüz:

  1. Bu sorguların dışında başka disk etkinliği yok. Emin misiniz? Başka kullanıcı sorgusu olmasa bile, arka plan işlemleri yapılıyor mu? Aynı makinede çalışan ve bazı IO'ları alabilen SQL Server harici işlemler var mı? Olmayabilir, ancak yalnızca sağlanan bilgilere dayanarak net değildir.
  2. 15 MB XML verisi döndürülüyor. Bu sayı neye dayanıyor? 1000 satırdan elde edilen bir tahmin, satır başına ortalama 15k XML verisi? Veya bu sorgu için alınanların programlı bir toplamı? Sadece bir tahminse, XML verilerinin dağılımı basit bir ortalama ile ima edilen şekilde bile olmayabileceğinden buna güvenmem.
  3. XML Sıkıştırma yardımcı olabilir. Sıkıştırmayı .NET'te tam olarak nasıl yapardınız? Via GZipStream veya DeflateStream sınıfları? Bu sıfır maliyetli bir seçenek değildir. Kesinlikle bazı verileri büyük bir yüzde oranında sıkıştıracaktır, ancak her seferinde verileri sıkıştırmak / açmak için ek bir işleme ihtiyacınız olacağından daha fazla CPU gerektirecektir. Bu plan ayrıca aşağıdakileri yapma yeteneğinizi de tamamen ortadan kaldıracaktır:

    • aracılığıyla sorgu XML veri .nodes, .value, .query, ve .modifyXML fonksiyonları.
    • XML verilerini indeksler.

      XMLVeri türünün, öğe ve öznitelik adlarını bir sözlükte depolaması, her öğeye bir tamsayı dizin kimliği ataması ve ardından bu tamsayı kimliğini kullanması için , veri türünün zaten optimize edildiğini (XML'nin "çok fazla yedekli olduğunu belirttiğinizden) lütfen unutmayın. (dolayısıyla her kullanım için tam adı tekrarlamaz veya öğeler için kapanış etiketi olarak tekrarlamaz). Gerçek veriler ayrıca yabancı beyaz boşluğa sahiptir. Bu nedenle çıkarılan XML belgeleri orijinal yapılarını korumaz ve boş öğeler neden <element />içeri girmiş gibi çıkarılır<element></element>. Bu nedenle, GZip (veya başka bir şey) ile sıkıştırmadan elde edilen kazançlar, yalnızca beklenenden daha fazla iyileştirilebilecek ve büyük olasılıkla kaybına değmeyecek çok daha küçük bir yüzey alanı olan eleman ve / veya nitelik değerlerini sıkıştırarak bulunur. doğrudan yukarıda belirtildiği gibi yetenekler.

      Lütfen XML verilerinin sıkıştırılmasının ve VARBINARY(MAX)sonucun saklanmasının LOB erişimini ortadan kaldırmayacağını, yalnızca azaltacağını unutmayın. Satırdaki verilerin geri kalanının boyutuna bağlı olarak, sıkıştırılmış değer sıraya sığabilir veya yine de LOB sayfaları gerektirebilir.

Bu bilgi, yardımcı olmakla birlikte, neredeyse yeterli değildir. Sorgu performansını etkileyen birçok faktör vardır, bu yüzden neler olup bittiğinin çok daha ayrıntılı bir resmine ihtiyacımız var.

Bilmediklerimiz, ancak aşağıdakilere ihtiyacımız var:

  1. SELECT *Maddenin performansı neden önemlidir? Bu, kodda kullandığınız bir kalıp mı? Öyleyse neden?
  2. Yalnızca XML sütununu seçmenin performansı nedir? Sadece yaparsanız istatistik ve zamanlama nedir SELECT TOP 1000 XmlColumn FROM TABLE;?
  3. Bu 1000 satırı döndürmek için gereken 20 - 25 saniyenin ne kadarı ağ faktörleriyle (veriyi telden alırken) ve müşteri faktörleriyle ne kadar ilgilidir (yaklaşık 15 MB'ı artı olmayan XML verilerini SSMS'deki ızgaraya veya muhtemelen diske kaydetme)?

    Operasyonun bu iki yönünü çarpanlarına ayırmak bazen verileri döndürmemek suretiyle yapılabilir. Şimdi, bir Geçici Tablo veya Tablo Değişkeni seçmeyi düşünebiliriz, ancak bu sadece birkaç yeni değişken getirecektir (yani tempdb, İşlem Günlüğü yazarları için disk G / Ç , tempdb verilerinin ve / veya günlük dosyasının otomatik olarak büyümesi, Tampon Havuzundaki boşluk vb.). Tüm bu yeni faktörler aslında sorgu süresini artırabilir. Bunun yerine, tipik olarak sütunları SQL_VARIANTher yeni satırla (yani SELECT @Column1 = tab.Column1,...) üzerine yazılan değişkenlere (uygun veri tipinin; değil ) depolarım .

    ANCAK , bu DBA.StackExchange S ve C'de @PulWhite tarafından işaret edildiği gibi, Mantıksal LOB verilerine erişirken farklı araştırmalar, PasteBin'de yayınlanan kendi ek araştırmalarım ( LOB okumaları için çeşitli senaryoları test etmek için T-SQL betiği ) , LOB sürekli arasında erişilebilir değildir SELECT, SELECT INTO, SELECT @XmlVariable = XmlColumn, SELECT @XmlVariable = XmlColumn.query(N'/'), ve SELECT @NVarCharVariable = CONVERT(NVARCHAR(MAX), XmlColumn). Yani seçeneklerimiz burada biraz daha sınırlı, ama işte neler yapılabilir:

    1. SSMS veya SQLCMD.EXE içinde SQL Server çalıştıran sunucuda sorguyu yürüterek ağ sorunlarını dışlayın.
    2. Sorgu Seçenekleri -> Sonuçlar -> Izgara'ya gidip "Yürütmeden sonra sonuçları sil" seçeneğini işaretleyerek SSMS'deki istemci sorunlarını ortadan kaldırın. Bu seçeneğin mesajlar da dahil olmak üzere TÜM çıktıları önleyeceğini, ancak SSMS'nin her satır başına belleği ayırması ve ardından ızgaraya çizmesi için geçen süreyi göz ardı etmekte faydalı olabileceğini lütfen unutmayın.
      Alternatif olarak, sqlCmd.exe aracılığıyla sorguyu yürütmek ve üzeri hiçbir yere gitmek için çıktı yönlendirmek olabilir: -o NUL:.
  4. Bu sorgu ile ilişkili bir Bekleme Türü var mı? Evet ise, bu Bekleme Türü nedir?
  5. Döndürülen sütunlar için gerçek veri boyutu nedir ? "TOP 1000" satırlarının toplam verilerin orantısız olarak büyük bir bölümünü içermesi durumunda, bu sütunun tüm tablodaki ortalama boyutu önemli değildir . TOP 1000 satırları hakkında bilgi edinmek istiyorsanız, bu satırlara bakın. Lütfen aşağıdakileri çalıştırın:XMLXML

    SELECT TOP 1000 tab.*,
           SUM(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [TotalXmlKBytes],
           AVG(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [AverageXmlKBytes]
           STDEV(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [StandardDeviationForXmlKBytes]
    FROM   SchemaName.TableName tab;
  6. Kesin tablo şema. Lütfen tüm dizinler dahil olmak üzere ifadenin tamamını CREATE TABLE belirtin.
  7. Sorgu planı? Bu gönderebileceğiniz bir şey mi? Bu bilgi muhtemelen hiçbir şeyi değiştirmeyecektir, ancak bunun yanlış olmayacağını ve yanlış olmayacağını tahmin etmekten daha iyi olmayacağını bilmek daha iyidir ;-)
  8. Veri dosyasında fiziksel / harici parçalanma var mı? Burada büyük bir faktör olmasa da, SSD veya Süper Pahalı SATA yerine "tüketici sınıfı SATA" kullandığınızdan, özellikle optimal olmayan sektörlerin etkisi, özellikle bu sektörlerin sayısı kadar, daha belirgin olacaktır. okunması gereken artış.
  9. Aşağıdaki sorgunun kesin sonuçları nelerdir :

    SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(),
                              OBJECT_ID(N'dbo.SchemaName.TableName'), 1, 0, N'LIMITED');

GÜNCELLEME

Bana benzer bir deneyim yaşayıp yaşamadığımı görmek için bu senaryoyu yeniden oluşturmaya çalışmalıydım. Bu nedenle, birkaç sütunlu bir tablo oluşturdum (Sorudaki belirsiz açıklamaya benzer) ve sonra 1 milyon satırla doldurdum ve XML sütununda satır başına yaklaşık 15k veri var (aşağıdaki koda bakın).

Ne buldum SELECT TOP 1000 * FROM TABLEilk kez 8 saniye içinde tamamlanmış ve daha sonra her seferinde 2-4 saniye (evet, DBCC DROPCLEANBUFFERSher SELECT *sorgu çalıştırmadan önce yürütme ) olduğunu. Ve birkaç yaşındaki dizüstü bilgisayarım hızlı değil : SQL Server 2012 SP2 Developer Edition, 64 bit, 6 GB RAM, çift 2.5 Ghz Core i5 ve 5400 RPM SATA sürücü. Ayrıca SSMS 2014, SQL Server Express 2014, Chrome ve diğer pek çok şeyi çalıştırıyorum.

Sistemimin yanıt süresine bağlı olarak, 20-25 saniyelik yanıt süresinin nedenini daraltmaya yardımcı olmak için daha fazla bilgiye ihtiyacımız olduğunu (tablo ve veriler hakkında ayrıntılar, önerilen testlerin sonuçları vb.) Tekrarlayacağım. görüyorsunuz.

SET ANSI_NULLS, NOCOUNT ON;
GO

IF (OBJECT_ID(N'dbo.XmlReadTest') IS NOT NULL)
BEGIN
    PRINT N'Dropping table...';
    DROP TABLE dbo.XmlReadTest;
END;

PRINT N'Creating table...';
CREATE TABLE dbo.XmlReadTest 
(
    ID INT NOT NULL IDENTITY(1, 1),
    Col2 BIGINT,
    Col3 UNIQUEIDENTIFIER,
    Col4 DATETIME,
    Col5 XML,
    CONSTRAINT [PK_XmlReadTest] PRIMARY KEY CLUSTERED ([ID])
);
GO

DECLARE @MaxSets INT = 1000,
        @CurrentSet INT = 1;

WHILE (@CurrentSet <= @MaxSets)
BEGIN
    RAISERROR(N'Populating data (1000 sets of 1000 rows); Set # %d ...',
              10, 1, @CurrentSet) WITH NOWAIT;
    INSERT INTO dbo.XmlReadTest (Col2, Col3, Col4, Col5)
        SELECT  TOP 1000
                CONVERT(BIGINT, CRYPT_GEN_RANDOM(8)),
                NEWID(),
                GETDATE(),
                N'<test>'
                  + REPLICATE(CONVERT(NVARCHAR(MAX), CRYPT_GEN_RANDOM(1), 2), 3750)
                  + N'</test>'
        FROM        [master].[sys].all_columns sac1;

    IF ((@CurrentSet % 100) = 0)
    BEGIN
        RAISERROR(N'Executing CHECKPOINT ...', 10, 1) WITH NOWAIT;
        CHECKPOINT;
    END;

    SET @CurrentSet += 1;
END;

--

SELECT COUNT(*) FROM dbo.XmlReadTest; -- Verify that we have 1 million rows

-- O.P. states that the "clustered index fragmentation is close to 0%"
ALTER INDEX [PK_XmlReadTest] ON dbo.XmlReadTest REBUILD WITH (FILLFACTOR = 90);
CHECKPOINT;

--

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 * FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,       physical reads 1,     read-ahead reads 4436,
              lob logical reads 5676, lob physical reads 1, lob read-ahead reads 3967.

 SQL Server Execution Times:
   CPU time = 171 ms,  elapsed time = 8329 ms.
*/

Ve, LOB olmayan sayfaları okumak için harcanan zamanı hesaba katmak istediğimiz için, XML sütunu (yukarıda önerdiğim testlerden biri) dışında tümünü seçmek için aşağıdaki sorguyu çalıştırdım. Bu, 1,5 saniyede oldukça tutarlı bir şekilde geri döner.

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 ID, Col2, Col3, Col4 FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,    physical reads 1,     read-ahead reads 4436,
              lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1666 ms.
*/

Sonuç (şimdilik)
Senaryonuzu yeniden oluşturma girişimime dayanarak, SATA sürücüsünü veya sıralı olmayan G / Ç'yi 20-25 saniyenin ana nedeni olarak gösterebileceğimizi düşünmüyorum, özellikle de hala XML sütunu dahil edilmediğinde sorgunun ne kadar hızlı döndüğünü bilmiyorum. Ve gösterdiğiniz çok sayıda Mantıksal Okuma (LOB olmayan) çoğaltmayı başaramadım, ancak bunun ve ifadesinin ışığında her satıra daha fazla veri eklemem gerektiğini hissediyorum :

Tablo sayfalarının ~% 90'ı LOB_DATA

sys.dm_db_index_physical_statsTablomda , her biri 15k'nin üzerinde XML verisi olan 1 milyon satır var ve 2 milyon LOB_DATA sayfası olduğunu gösteriyor. Kalan% 10 daha sonra 222k IN_ROW veri sayfası olacaktır, ancak bunlardan sadece 11.630'um var. Yani bir kez daha, gerçek tablo şeması ve gerçek veriler hakkında daha fazla bilgiye ihtiyacımız var.



10

sadece boyutu nedeniyle değil, aynı zamanda SQL Server kümelenmiş dizini etkili bir şekilde tarayamadığı için LOB_DATA sayfalarının yavaş taramalara neden olabileceğini düşünerek düzeltiyorum

Evet, satırda saklanmayan LOB verilerinin okunması, sıralı IO yerine rastgele IO'ya yol açar. Neden hızlı veya yavaş olduğunu anlamak için burada kullanılan disk performans ölçüsü Rastgele Okuma IOPS'udur.

LOB verileri, kümelenmiş dizindeki veri sayfasının gerçek LOB verisine işaret eden bir LOB kök yapısına sahip bir LOB Veri sayfasına işaret ettiği bir ağaç yapısında saklanır . Kümelenmiş dizindeki kök düğümleri gezerken SQL Server satır içi verileri yalnızca sıralı okumalarla alabilir. LOB verilerini almak için SQL Server'ın diskte başka bir yere gitmesi gerekir.

Bir SSD diskine geçtiyseniz, bir SSD için rastgele IOPS dönen bir diskten çok daha yüksek olduğu için bundan çok fazla acı çekmeyeceğinizi tahmin ediyorum.

böyle bir tablo yapısına / veri modeline sahip olmak makul kabul edilir mi?

Evet olabilir. Bu tablonun sizin için ne yaptığına bağlıdır.

Genellikle SQL Server'da XML ile ilgili performans sorunları, XML'i sorgulamak için T-SQL kullanmak istediğinizde ve daha da fazlası, burada bir yan tümcede veya birleştirmede bir yüklemede XML değerlerini kullanmak istediğinizde ortaya çıkar. Bu durumda, özellik tanıtımına veya seçici XML dizinlerine veya bunun yerine XML'i tablolara parçalayan tablo yapılarınızın yeniden tasarımına bakabilirsiniz .

Sıkıştırmayı denedim

Bunu bir üründe 10 yıldan biraz önce yaptım ve o zamandan beri pişman oldum. Gerçekten T-SQL kullanarak veri ile çalışamıyorum özledim, bu yüzden kaçınılabilir eğer kimseye bunu tavsiye etmem.


Cevabınız için çok teşekkürler. Sıkıştırma ile ilgili olarak: T-SQL'den gelen verileri sorgulama gereği açıkça depolanan verilerin doğasına bağlı olduğundan, böyle katı bir anti-önerinin haklı olup olmadığından emin değilim. Benim durumumda, şimdilik sıkıştırma ile gitmeye karar verdim.
Alexander Shelemin
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.