Sorudaki örnekler aynı sonuçları vermez ( OFFSET
örneğin, birer birer hata vardır). Aşağıdaki güncellenmiş formlar bu sorunu düzeltir, ROW_NUMBER
vaka için fazladan sıralamayı kaldırır ve çözümü daha genel hale getirmek için değişkenleri kullanır:
DECLARE
@PageSize bigint = 10,
@PageNumber integer = 3;
WITH Numbered AS
(
SELECT TOP ((@PageNumber + 1) * @PageSize)
o.*,
rn = ROW_NUMBER() OVER (
ORDER BY o.[object_id])
FROM #objects AS o
ORDER BY
o.[object_id]
)
SELECT
x.name,
x.[object_id],
x.principal_id,
x.[schema_id],
x.parent_object_id,
x.[type],
x.type_desc,
x.create_date,
x.modify_date,
x.is_ms_shipped,
x.is_published,
x.is_schema_published
FROM Numbered AS x
WHERE
x.rn >= @PageNumber * @PageSize
AND x.rn < ((@PageNumber + 1) * @PageSize)
ORDER BY
x.[object_id];
SELECT
o.name,
o.[object_id],
o.principal_id,
o.[schema_id],
o.parent_object_id,
o.[type],
o.type_desc,
o.create_date,
o.modify_date,
o.is_ms_shipped,
o.is_published,
o.is_schema_published
FROM #objects AS o
ORDER BY
o.[object_id]
OFFSET @PageNumber * @PageSize - 1 ROWS
FETCH NEXT @PageSize ROWS ONLY;
ROW_NUMBER
Plan tahmini maliyeti vardır 0.0197935 :
OFFSET
Plan tahmini maliyeti vardır 0.0196955 :
Bu, 0.000098 tahmini maliyet biriminden tasarruf sağlar ( OFFSET
her bir satır için bir satır numarası döndürmek istiyorsanız , plan ekstra işleçler gerektirecektir). OFFSET
Plan hala, genel anlamda biraz daha ucuz olacak, ama tahmini maliyeti tam olarak bu olduğunu hatırlıyorum - Gerçek test hala gereklidir. Her iki plandaki maliyetin büyük kısmı, girdi kümesinin tümünün maliyetidir, bu nedenle yardımcı dizinler her iki çözüme de fayda sağlayacaktır.
Sabit değişmez değerlerin kullanıldığı yerlerde (örneğin OFFSET 30
orijinal örnekte), optimizer, tam sıralama ve ardından Top yerine yerine bir TopN Sıralaması kullanabilir. TopN ihtiyaç duyduğu satırlar Sıralama sabit bir gerçek ve <= 100 (toplamı olduğunda OFFSET
ve FETCH
) yürütme motoru kullanarak farklı bir sıralama algoritması sıralama genelleştirilmiş TopN daha hızlı gerçekleştirebilir. Her üç durum da genel olarak farklı performans özelliklerine sahiptir.
Optimize edicinin ROW_NUMBER
sözdizimi desenini otomatik olarak kullanmak için neden değiştirmediğine gelince OFFSET
, bunun birkaç nedeni vardır:
- Mevcut tüm kullanımlara uygun bir dönüşüm yazmak neredeyse imkansız
- Bazı çağrı sorgularının otomatik olarak dönüştürülmesi ve başkalarının kafa karıştırıcı olmaması
OFFSET
Plan her durumda daha iyi olması garanti edilmez
Yukarıdaki üçüncü nokta için bir örnek, çağrı kümesinin oldukça geniş olduğu bir yerde meydana gelir. Kümelenmemiş bir dizin kullanarak gerekli anahtarları aramak ve dizini OFFSET
veya ile taramaya kıyasla kümelenmiş dizine manuel olarak bakmak çok daha verimli olabilir ROW_NUMBER
. Orada değerlendirmek üzere ek sorunlar çağrıların uygulaması toplamda kaç satır veya sayfa bilmek gerekiyorsa. Burada 'anahtar arama' ve 'dengeleme' yöntemlerinin göreceli esası hakkında iyi bir tartışma var .
Genel olarak, insanların OFFSET
ayrıntılı sorgulamadan sonra, uygunsa, sayfalama sorgularını değiştirmek için bilinçli bir karar vermeleri daha iyidir .