WHERE yan tümcem “dahil” sütunundan neden yararlanıyor?


12

Bu cevaba göre , kısıtlamak için kullanılan sütunlar üzerine bir indeks oluşturulmadıkça, sorgu bir endeksten faydalanmayacaktır.

Bu tanım var:

CREATE TABLE [dbo].[JobItems] (
    [ItemId]             UNIQUEIDENTIFIER NOT NULL,
    [ItemState]          INT              NOT NULL,
    [ItemPriority]       INT NOT NULL,
    [CreationTime]       DATETIME         NULL DEFAULT GETUTCDATE(),
    [LastAccessTime]     DATETIME         NULL DEFAULT GETUTCDATE(),
     -- other columns
 );

 CREATE UNIQUE CLUSTERED INDEX [JobItemsIndex]
    ON [dbo].[JobItems]([ItemId] ASC);
 GO

CREATE INDEX [GetItemToProcessIndex]
    ON [dbo].[JobItems]([ItemState], [ItemPriority], [CreationTime])
    INCLUDE (LastAccessTime);
GO

ve bu sorgu:

UPDATE TOP (150) JobItems 
SET ItemState = 17 
WHERE 
    ItemState IN (3, 9, 10)
    AND LastAccessTime < DATEADD (day, -2, GETUTCDATE()) 
    AND CreationTime < DATEADD (day, -2, GETUTCDATE());

Ben gerçek planı gözden geçirdi, ve sadece bir dizin arama tam olarak olduğu gibi WHERE- ek hiçbir "yer imi aramaları" LastAccessTime, ikincisi sadece bir "dizin" dizinine dahil, "dahil" olsa bile.

Bana öyle geliyor ki bu davranış, sütunun sadece "dahil" değil, dizinin bir parçası olması gerektiği kuralıyla çelişiyor.

Gözlemlediğim davranış doğru mu? Eklenen WHEREbir sütunun sağladığı yararlarımın veya sütunun dizinin bir parçası olması gerektiğini önceden nasıl anlayabilirim ?


Yine de ItemStatedeğere göre arama yapabilir , ancak Arama, Endeksiniz aşağıdaki gibi yapılandırılmış gibi verimli olmayacaktır(ItemState, CreationTime, LastAccessTime)
Mark Sinkinson

1
@MarkSinkinson or just(ItemState, CreationTime) INCLUDE (LastAccessTime)
ypercubeᵀᴹ

@sharptooth, sahip olduğunuz cevabın ("sorguyu kısıtlamak için kullanılan sütunlar üzerine bir indeks oluşturulmadığı sürece bir endeksten faydalanmayacağını" söylemez). Üzerinde bir dizin (a,b)için bir sorgu için en iyi olmadığını SELECT a FROM t WHERE b=5;ve bir dizin üzerinde (b) INCLUDE (a)çok daha iyi olduğunu söylüyor .
ypercubeᵀᴹ

Yanıtlar:


9

Tahmininiz, Tahmininizden farklıdır.

Dizinde sıralanan verileri aramak için bir Arama İsteği kullanılır. Bu durumda, ilgilendiğiniz her bir ItemState için bir tane olmak üzere üç arama yapılacaktır. Bunun ötesinde, veriler ItemPriority düzenindedir, bu nedenle başka bir "Seek" işlemi yapılamaz.

Ancak veriler döndürülmeden önce, Kalıntı Tahmini olarak adlandırdığım Predicate'i kullanarak her satırı kontrol eder. Arama Predicate'in sonuçları üzerinde yapılır.

Dahil edilen herhangi bir sütun, sipariş edilen verilerin bir parçası değildir, ancak fazladan Arama yapmak zorunda kalmadan Artık Tahmin'i karşılamak için kullanılabilir.

Bu konuda yazdığım materyalleri Sargability etrafında görebilirsiniz. SQLBits'de, özellikle http://bit.ly/Sargability'de bir oturum olup olmadığını kontrol edin

Düzenleme: Residuals etkisini daha iyi göstermek için OPTION (QUERYTRACEON 9130), Residuals ayrı bir Filter operatörü (aslında bakiye Seek operatörüne taşınmadan önce aslında planın önceki bir sürümü) ayırır belgelenmemiş kullanarak sorguyu çalıştırın . Filtreye bırakılan satır sayısı ile etkisiz bir Aramanın etkisini açıkça gösterir.

ItemState'teki IN yan tümcesi nedeniyle, sola iletilen verilerin aslında ItemPriority sırasında değil ItemState düzeninde olduğunu belirtmek gerekir. ItemState üzerinde bileşik bir dizin ve ardından tarihlerden biri (ör. (ItemState, LastAccessTime)) üç Seçineye sahip olmak için kullanılabilir (Seek Predicate'in bir Seek operatörü içinde üç selam gösterdiğini unutmayın), her biri iki seviyeye karşı, yine de ItemState düzeninde (ör. bir şeyden daha az ItemState = 3 ve LastAccessTime, bir şeyden daha az ItemState = 9 ve LastAccessTime ve daha sonra bir şeyden daha az ItemState = 10 ve LastAccessTime).

(ItemState, LastAccesTime, CreationTime) üzerindeki bir dizin (ItemState, LastAccessTime) üzerinde birinden daha yararlı olmaz çünkü CreationTime seviyesi yalnızca Aramanız belirli bir ItemState ve LastAccessTime birleşimi içinse yararlıdır. F ile başlayan Soyadı ile ilgileniyorsanız telefon rehberinin FirstName düzeninde olmaması gibi.

Bileşik bir dizin istiyorsanız, ancak önceki sütunları kullanma şekliniz nedeniyle Seek Tahminlerindeki sonraki sütunları asla kullanamayacaksanız, bunları daha az yer kaplayan sütunlar olarak da dahil edebilirsiniz. (daha yüksek düzeylerde değil, yalnızca dizinin yaprak düzeyinde depolandıkları için), ancak yine de aramalardan kaçınabilir ve Artık tahminlerde kullanılabilir.

Artık Tahmin terimi uyarınca - bu bir Aramanın bu özelliği için kendi terimim. Bir Birleştirme Üyeliği açıkça eşdeğeri bir Kalıntı Tahmini olarak adlandırır ve Hash Match, bir Probe Kalıntısı olarak adlandırır (karma için eşleşirseniz TSA'dan alabilirsiniz). Ama bir Aramaya sadece Predicate diyorlar ki bu da olduğundan daha az kötü görünüyor.


3

GetItemToProcessIndex tam olarak aranamaz çünkü nerede yan tümceniz açıktır ItemState + LastAccessTime + CreationTime. Dizinlenmiş sütunlar ve where cümlesi mükemmel bir eşleşme değil.

Üzerinde bir kaplama dizini oluşturursanız ItemState + LastAccessTime + CreationTime, GetItemToProcessIndex'ten aldığınız her eşleşme için, Birincil Anahtarınızın (ItemId) değerini de alırsınız. Sadece 2. tarihin bir eşleşme olduğundan emin olmak zorundadır.

Daha sonra sayfasındaki satırın konumuna atlamak ve güncellemek için ihtiyacınız olan tek şey budur.

Geçerli dizininizle, sunucunun istediğiniz ItemState ile satır bulmasına yardımcı olabilir, ancak yine de LastAccessTime + CreationTime'da doğru eşleşmeleri bulmak için dizinden hepsini okumak zorunda kalır. Tarih tahminlerine ve eşleşen kümenin boyutuna ve nelerin hariç tutulması gerektiğine bağlı olarak, yalnızca ItemState ve ikinci sütunu (1. endeksli tarih) arayacak olan 3 sütunda mükemmel bir kaplama dizininden çok daha fazla IO ile sonuçlanabilir. . Dizine alınan ikinci tarih de dahil edilebilir. Ek sütunlar bu sütunlar arasında dizine eklenmemelidir, ancak 4. sütun olarak kullanılabilir (rob'ın fazladan sütunlar hakkındaki cevabına bakın).

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.