Kümelenmiş İndeksi Olan Bir Tabloya Verimli INSERT


28

TRACKING_NUMBER sütunundaki kümelenmiş bir dizini içeren bir tabloya satır ekleyen bir SQL deyim var.

ÖRNEĞİN:

INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC) 
SELECT TRACKING_NUMBER, COL_B, COL_C 
FROM STAGING_TABLE

Sorum şu - kümelenmiş dizin sütunu için SELECT deyiminde bir ORDER BY deyimi kullanmak yardımcı oluyor mu, yoksa elde edilen herhangi bir kazanç ORDER BY deyimi için gereken fazladan sıralama tarafından reddedilir mi?

Yanıtlar:


18

Diğer cevaplar zaten belirtildiği gibi, SQL Server açıkça satırların önce kümelenmiş dizin sıralamasında sıralandığından emin olabilir ya da olmayabilir insert.

Bu, plandaki kümelenmiş indeks operatörünün DMLRequestSortözellik setine sahip olup olmamasına bağlıdır (sırayla eklenen tahmini satır sayısına bağlıdır).

SQL Server'ın bunu her ne sebeple küçümsemediğini tespit ederseniz ORDER BY, SELECTsayfa bölünmelerini en aza indirmek ve INSERTişlemden parçalanmaya neden olmak için sorguya açık bir şekilde eklemekten faydalanabilirsiniz.

Örnek:

use tempdb;

GO

CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))

CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))

GO

DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)

INSERT INTO @T(N)
SELECT number 
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499

/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2

/*Same operation using explicit sort*/    
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;  


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;  

Bu Tkitlesel parçalanmış gösterir

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536             92535                92535                67.1668272794663               250000
99.5                         200                  200                  74.2868173956017               92535
0                            1                    1                    32.0978502594514               200

Ancak T2parçalanma için asgari düzeyde

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376                        262                  62500                99.456387447492                250000
2.1551724137931              232                  232                  43.2438349394613               62500
0                            1                    1                    37.2374598468001               232

Tersine, bazen verilerin önceden sıralandığını ve gereksiz bir sıralamadan kaçınmak istediğinizi bildiğinizde, SQL Server'ı satır sayısını küçümsemeye zorlamak isteyebilirsiniz. Dikkate değer bir örnek, newsequentialidkümelenmiş bir dizin anahtarına sahip bir tabloya çok sayıda satır eklerken verilebilir . Denali'den önceki SQL Server sürümlerinde, SQL Server gereksiz ve potansiyel olarak pahalı bir sıralama işlemi ekler . Bu tarafından önlenebilir

DECLARE @var INT =2147483647

INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar

SQL Server daha sonra Bar, plana bir sıralama eklendiği eşiğin altında olan boyutuna bakılmaksızın 100 satır ekleneceğini tahmin edecektir . Bununla birlikte, aşağıdaki açıklamalarda belirtildiği gibi, bu, ekin maalesef minimum kayıt işleminden yararlanamayacağı anlamına gelir.



12

İyileştirici, verileri yerleştirmeden önce sıralamanın daha etkili olacağına karar verir, bu da ekleme operatörünün akışının yukarısında bir yerde olur. Sorgunuzun bir parçası olarak bir sıralama eklerseniz, iyimser, verilerin zaten sıralandığını fark etmeli ve tekrar yapmayı bırakmalıdır. Seçilen uygulama planının, hazırlama tablonuzdan eklenen satır sayısına bağlı olarak, çalışmadan çalışmaya değişebileceğini unutmayın.

İşlemin yürütme planlarını açık sıralama olsun ya da olmasın yakalayabilirseniz, bunları yorum için sorunuza ekleyin.

Düzenleme: 2011-10-28 17:00

@ Gonsalu'nun cevabı , sıralama işleminin her zaman gerçekleştiğini gösteriyor gibi görünüyor, durum böyle değil. Demo komut dosyaları gerekli!

Senaryolar oldukça genişledikçe, onları Gist'e taşıdım . Deney kolaylığı için, komut dosyaları SQLCMD modunu kullanır. Testler 2K5SP3, çift çekirdekli, 8GB'da çalışır.

Ekleme testleri üç senaryoyu kapsar:

  1. Veri kümelenmiş dizinin hedefle aynı sırada dizilmesi.
  2. Veri kümeleme indeksi ters sırada dizildi.
  3. Rasgele bir INT içeren col2 tarafından kümelenmiş evreleme verileri.

İlk çalıştırma, 25 satır ekleyerek.

İlk çalıştırma, 25 satır

Üç yürütme planının tümü aynıdır, planın hiçbir yerinde sıralama olmaz ve kümelenmiş dizin taraması "sıralı = yanlış" şeklindedir.

İkinci çalıştırma, 26 satır ekleyerek.

2. sıra, 26 sıra

Bu sefer planlar farklı.

  • Birincisi, kümelenmiş dizin taramasını sıralı olarak = false olarak gösterir. Kaynak veriler uygun şekilde sıralandığından hiçbir sıralama gerçekleşmedi.
  • İkincisinde, kümelenmiş dizin sıralandığı gibi tarar = true, geriye doğru. Bu nedenle bir sıralama işlemimiz yok, ancak sıralanacak verilere olan gereksinim, optimizer tarafından tanınır ve ters sırada tarar.
  • Üçüncüsü bir sıralama işlecini gösterir.

Bu yüzden, iyimserin gerekli olduğunu düşündüğü bir bahşiş noktası var. @ MartinSmith'in gösterdiği gibi, bu, eklenecek tahmini satırlara göre görünmektedir. Test cihazımda 25 bir sıralama gerektirmiyor, 26 (2K5SP3, çift çekirdekli, 8GB)

SQLCMD betiği, tablodaki satırların boyutunun değişmesine izin veren (sayfa yoğunluğunu değiştiren) ve dbo.MyTable'daki satır sayısını, ek eklerden önce içeren değişkenleri içerir. Testlerimden hiçbirinin devrilme noktası üzerinde etkisi yoktur.

Herhangi bir okuyucu bu kadar eğimli ise, lütfen komut dosyalarını çalıştırın ve bahşiş noktanızı yorum olarak ekleyin. Test ekipmanlarına ve / veya sürümlere göre değişip değişmediğini öğrenmek ister.

Düzenleme: 2011-10-28 20:15

Aynı teçhizatta fakat 2K8R2 ile tekrarlanan testler. Bu sefer devrilme noktası 251 sıradır. Yine, sayfa yoğunluğunu ve mevcut satır sayısını değiştirmenin bir etkisi yoktur.


8

ORDER BYİçinde fıkra SELECTaçıklamada gereksiz olduğunu.

Gereksizdir, çünkü eklenecek satırlar, sıralanmaları gerekiyorsa , yine de sıralanırlar.

Bir test davası oluşturalım.

CREATE TABLE #Test (
    id INTEGER NOT NULL
);

CREATE UNIQUE CLUSTERED INDEX CL_Test_ID ON #Test (id);

CREATE TABLE #Sequence (
    number INTEGER NOT NULL
);

INSERT INTO #Sequence
SELECT number FROM master..spt_values WHERE name IS NULL;

Gerçek sorgu planlarının metin gösterimini etkinleştirelim, böylece sorgu işlemcisi tarafından hangi görevlerin gerçekleştirildiğini görebiliriz.

SET STATISTICS PROFILE ON;
GO

Şimdi, INSERT2K ORDER BYyan tümce tümce tümce tümce olmadan olsun .

INSERT INTO #Test
SELECT number
  FROM #Sequence

Bu sorgu için gerçek yürütme planı şudur.

INSERT INTO #Test  SELECT number    FROM #Sequence
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

Gördüğünüz gibi, asıl INSERT gerçekleşmeden önce bir Sıralama işleci var.

Şimdi, tabloyu temizleyelim ve INSERT2k cümlesiyle birlikte tabloya satırları ORDER BYsokalım.

TRUNCATE TABLE #Test;
GO

INSERT INTO #Test
SELECT number
  FROM #Sequence
 ORDER BY number

Bu sorgu için gerçek yürütme planı şudur.

INSERT INTO #Test  SELECT number    FROM #Sequence   ORDER BY number
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

Bu INSERTcümle olmadan ifade için kullanılan aynı uygulama planı olduğuna dikkat edin ORDER BY.

Şimdi, Mark Smith başka bir cevapta gösterdiği için Sortişlem her zaman gerekli değildir (eğer eklenecek satır sayısı düşükse), ancak bu durumda fıkra hala gereksizdir, çünkü açık bir şekilde bile , hiçbir işlem yapılmaz. sorgu işlemcisi tarafından.ORDER BYORDER BYSort

INSERTMinimal olarak günlüğe kaydedilen kullanarak, bir ifadeyi kümelenmiş bir dizini içeren bir tabloya göre optimize edebilirsiniz INSERT, ancak bu sorunun kapsamı dışındadır.

Updated 2011-11-02: Mark Smith'in gösterdiği gibi , INSERTkümelenmiş bir dizine sahip bir tabloya her zaman sıralanması gerekmeyebilir - ORDER BYfıkra da bu durumda gereksizdir.

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.