ROW_NUMBER () AŞIRI (B BÖLMEYE GÖRE, ORDER BY C) (A, B, C) dizinini kullanmaz


12

Bu iki işlevi göz önünde bulundurun:

ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C)

ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C)

Anladığım kadarıyla, tam olarak aynı sonucu veriyorlar. Başka bir deyişle, PARTITION BYyan tümcedeki sütunları listelemenizin sırası önemli değildir.

Bir indeks varsa (A,B,C), optimizatörün bu indeksi her iki varyasyonda da kullanmasını bekledim.

Ancak, şaşırtıcı bir şekilde, optimize edici ikinci varyantta ekstra açık bir Sıralama yapmaya karar verdi.

SQL Server 2008 Standard ve SQL Server 2014 Express'te gördüm.

İşte onu yeniden oluşturmak için kullandığım tam bir komut dosyası.

Microsoft SQL Server 2014 üzerinde çalıştı - 12.0.2000.8 (X64) 20 Şubat 2014 20:04:26 Telif Hakkı (c) Windows NT 6.1 üzerinde Microsoft Corporation Express Edition (64 bit) (Derleme 7601: Service Pack 1)

ve Microsoft SQL Server 2014 (SP1-CU7) (KB3162659) - 12.0.4459.0 (X64) 27 Mayıs 2016 15:33:17 Telif Hakkı (c) Windows NT 6.1'de Microsoft Corporation Express Edition (64 bit) (Derleme 7601: Hizmet Paket 1)

ve kullanarak hem eski hem de yeni Kardinalite Tahmincisi OPTION (QUERYTRACEON 9481)ile OPTION (QUERYTRACEON 2312).

Tablo, dizin, örnek veri ayarlama

CREATE TABLE [dbo].[T](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [A] [int] NOT NULL,
    [B] [int] NOT NULL,
    [C] [int] NOT NULL,
    CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_ABC] ON [dbo].[T]
(
    [A] ASC,
    [B] ASC,
    [C] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, 
DROP_EXISTING = OFF, 
ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON)
GO

INSERT INTO [dbo].[T] ([A],[B],[C]) VALUES
(10, 20, 30),
(10, 21, 31),
(10, 21, 32),
(10, 21, 33),
(11, 20, 34),
(11, 21, 35),
(11, 21, 36),
(12, 20, 37),
(12, 21, 38),
(13, 21, 39);

Sorguları

SELECT -- AB
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- BA
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

Uygulama planları

A, B İLE BÖLME

AB

B, A İLE BÖLME

BA

Her ikisi de

her ikisi de

Gördüğünüz gibi, ikinci planın fazladan bir Sıralaması var. B, A, C tarafından sipariş edilir. Optimize edici, görünüşe göre, bununla PARTITION BY B,Aaynı olduğunu PARTITION BY A,Bve verileri yeniden sıraladığını fark edecek kadar akıllı değildir .

İlginçtir ki, üçüncü sorguda her iki varyantı da ROW_NUMBERvardır ve fazladan Sıralama yoktur! Plan, ilk sorgudakiyle aynıdır. (Sekans Projesi, ekstra sütun için Çıktı Listesi'nde fazladan ifadeye sahiptir, ancak fazladan Sıralama içermez). Yani, bu daha karmaşık durumda, iyileştirici PARTITION BY B,A, bunun aynı olduğunu anlayacak kadar akıllı görünüyordu PARTITION BY A,B.

Birinci ve üçüncü sorgularda Dizin Tarama işleci, Sıralı: Doğru özelliğine sahiptir, ikinci sorguda Yanlış'tır.

Daha da ilginç, bu şekilde üçüncü sorguyu yeniden yazarsam (iki sütun takas):

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

ekstra sıralama tekrar görünür!

Birisi biraz ışık tutabilir mi? Buradaki optimize edicide neler oluyor?


Yanıtlar:


2

Eğer geliştirici değilseniz ve içselliğini bilmiyorsanız, "iyimserde neler oluyor" sorusuna iyi bir kesin "cevap" yoktur.

Yorumları bir araya getireceğim.

Genel olarak, sorgunun sonucu doğru olduğundan, hata olarak adlandırmanın çok zor olacağı anlaşılıyor. Bazı durumlarda yürütme planı basitçe optimal değildir. ypercubeᵀᴹ , Martin Smith ve Aaron Bertrand buna "kaçırılmış optimizasyon" diyor.

  • Aynı planlar gibi görünüyor GROUP BY a,bve GROUP BY b,aaynı planları sağlıyor ancak PARTITION BYaynı dönüşümü kullanamıyor

  • Aynı pencere spesifikasyonuna sahip pencere fonksiyonlarının, seçim listesinde farklı bir spesifikasyona sahip bir tane ile ayrılması durumunda ekstra sıralama işlemine sahip olabileceği başka eksik optimizasyonlar da vardır.

  • Evet, bu başka bir kaçırılmış optimizasyon gibi görünüyor ve bunlardan çok var. Optimize edici insanlar tarafından yazılmıştır ve mükemmel değildir


Azalan Endeksler ile ilgili bir makale var . Itzik Ben-Gan tarafından endeks sıralaması, paralellik ve sıralama hesaplamaları . Orada Itzik azalan indeksleri tartışır ve ayrıca indeks tanımının yönünün pencere fonksiyonlarını bölümlerle nasıl etkilediğine dair bir örnek verir. ROW_NUMBEROptimize edicinin kaçınabileceği ekstra sıralama operatörüne sahip sorgu ve oluşturulan plan örnekleri gösterir .


Benim için pratik sonuç, optimizasyoncunun bu özelliğini akılda tutmak olacaktır. PARTITION BYPencere işlevlerini kullanırken , her zaman sütunları PARTITION BYlistelediğiniz sırayla dizinde listelendikleri sırayla eşleştirmeye çalışın . Önemli olmamasına rağmen.

Bu önlemin diğer bir tarafı, dizinlerinizi gözden geçirip dizin tanımındaki bazı sütunları değiştirmeye karar vermenizdir. Etkilenmeyecek gibi görünen bazı sorguları yanlışlıkla etkileyebileceğinizi unutmayın. Aslında bu, optimizatörün bu özelliğini fark ettim.

Bunu yapmazsanız, optimizer dizini tam potansiyeline sahip olamayabilir. Optimize edici en uygun planı seçse bile, bu plan, deyimdeki sütunların sırasını değiştirmek gibi sorguda en ufak bir masum değişiklikle daha az optimal olarak değişebilir SELECT.

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.