Birleştirilmiş bir hesaplanmış sütun var, basitçe birleştirilmiş sütunlardan oluşan bir masada.
CREATE TABLE dbo.T
(
ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
A VARCHAR(20) NOT NULL,
B VARCHAR(20) NOT NULL,
C VARCHAR(20) NOT NULL,
D DATE NULL,
E VARCHAR(20) NULL,
Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL
);
Bu Comp
benzersiz değildir ve D, her bir kombinasyonun tarihinden itibaren geçerlidir A, B, C
, bu nedenle her birinin bitiş tarihini almak için aşağıdaki sorguyu kullanıyorum A, B, C
(temel olarak Comp'in aynı değeri için bir sonraki başlangıç tarihi):
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1
WHERE t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;
Daha sonra bu sorgulamaya yardımcı olmak için hesaplanan sütuna bir dizin ekledim:
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Ancak sorgu planı beni şaşırttı. Bunu söyleyen bir maddeye sahip olduğumdan D IS NOT NULL
ve bunu Comp
sıraladığımdan ve hesaplanan sütundaki dizinin t1 ve t2'yi taramak için kullanılabileceğini, ancak dizinin dışındaki herhangi bir sütuna atıfta bulunmadığımı düşünürdüm, ancak kümelenmiş bir dizin gördüm tarayın.
Bu yüzden, daha iyi bir plan yapıp yapmadığını görmek için bu endeksin kullanımını zorladım:
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE t1.D IS NOT NULL
ORDER BY t1.Comp;
Bu planı veren
Bu, bir Anahtar aramanın kullanıldığını gösterir; bunların ayrıntıları:
Şimdi, SQL-Server belgelerine göre:
Sütun, CREATE TABLE veya ALTER TABLE ifadesinde PERSISTED olarak işaretlenmişse, deterministik ancak kesin olmayan bir ifadeyle tanımlanan bir hesaplanmış sütun üzerinde bir dizin oluşturabilirsiniz. Bu, Veritabanı Motorunun hesaplanan değerleri tabloda sakladığı ve hesaplanan sütunun bağlı olduğu diğer sütunlar güncellendiğinde bunları güncellediği anlamına gelir. Veritabanı Altyapısı, bu kalıcı değerleri, sütunda bir dizin oluşturduğunda ve dizine bir sorguda başvurulduğunda kullanır. Bu seçenek, Database Engine, hesaplanan sütun ifadelerini döndüren bir fonksiyonun, özellikle de .NET Framework'te oluşturulan bir CLR fonksiyonunun hem deterministik hem de kesin olup olmadığını doğrulukla kanıtlayamadığında hesaplanan bir sütunda bir dizin oluşturmanıza olanak sağlar.
Öyleyse, dokümanlar "Veritabanı Altyapısı tablodaki hesaplanan değerleri depolar" dediğinde ve değer de dizinimde saklanıyorsa, başvuruda bulunmadıklarında neden A, B ve C almak için bir Anahtar Arama gerekli? hiç sorgu? Comp hesaplamak için kullanıldığını sanıyorum, ama neden? Ayrıca, sorgu neden dizini kullanabilir t2
, ancak kullanmıyor t1
?
NB SQL Server 2008'i etiketledim, çünkü bu ana sorunumun açık olduğu sürüm, ancak 2012'de de aynı davranışı alıyorum.