SELECT ve GROUP BY yan tümcesinde SQL Hesaplanan Alan


11

Genellikle MS SQL Server veritabanlarımı sorgularken, bunun gibi hesaplanmış bir alan oluşturmam gerekiyor

(CASE WHEN A.type = 'Workover' THEN 'Workover' 
      ELSE (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' 
                 WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' 
                 WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' 
                 ELSE 'Other' 
            END)
END)

ve sonra sonuçlarımı bu hesaplanan alana göre gruplandırmam gerekiyor (diğerleri arasında). Bu nedenle, SELECT ve GROUP BY deyimlerinde aynı hesaplamaya sahibim. SQL Server aslında bu hesaplamaları iki kez yapıyor mu, yoksa sadece bir kez yapmak için yeterince akıllı mı?

Yanıtlar:


13

SELECT ve GROUP BY deyimlerinde aynı hesaplamaya sahibim. SQL Server aslında bu hesaplamaları iki kez yapıyor mu, yoksa sadece bir kez yapmak için yeterince akıllı mı?

Basit yanıt, SQL Server'ın yürütme zamanında ne zaman ve kaç kez skaler ifadenin değerlendirileceği konusunda genel bir garanti vermemesidir.

Optimize edici ve yürütme motoru içinde, skaler ifadelerin yerleştirilmesi, yürütülmesi ve önbelleğe alınması ile ilgili her türlü karmaşık (ve belgesiz) davranış vardır. Çevrimiçi Kitaplar'ın bunun hakkında söyleyecek çok şeyi yoktur , ancak söylediği şey şudur:

Skaler hesaplama

Bu, daha önce bahsettiğim davranışlardan birini, ifadelerin ertelenmesini açıklar. Bu blog yazısında (ki her zaman değişebilir) diğer mevcut davranışlardan bazıları hakkında yazdım .

Diğer bir husus, sorgu optimize edici tarafından kullanılan maliyet modelinin şu anda skaler ifadeler için maliyet tahmini yolunda fazla bir şey yapmamasıdır . Güçlü bir maliyet çerçevesi olmadan, mevcut sonuçlar geniş sezgisel tarama veya saf şansa dayanmaktadır.

Çok basit ifadeler için, ifadenin çoğu durumda bir kez mi yoksa birçok kez mi değerlendirileceği pek fark etmez. Bununla birlikte, ifade çok sayıda kez gereksiz olarak değerlendirildiğinde performansın olumsuz etkilendiği veya sorgulamanın yürütmenin paralel bir dalında değerlendirmenin avantajlı olacağı tek bir iş parçacığında gerçekleştiği büyük sorgularla karşılaştım. plan.

Özetle, mevcut davranış tanımlanmamıştır ve yürütme planlarında ne olduğunu anlamanıza yardımcı olacak çok fazla bir şey yoktur (ve blog yayınında olduğu gibi ayrıntılı motor davranışlarını incelemek için bir hata ayıklayıcı eklemek her zaman uygun olmayacaktır).

Skaler değerlendirme sorunlarının performans açısından önemli olduğu vakalarla karşılaşırsanız, sorunu Microsoft Destek ile gündeme getirin. Bu, ürünün gelecekteki sürümlerini iyileştirmek için geri bildirim sağlamanın en iyi yoludur.


3

Sorunuzla ilgili yorumda belirtildiği gibi, cevap (en azından benim deneyimime göre) "evet". SQL Server genellikle yeniden hesaplamayı önleyecek kadar akıllıdır. SQL Server Management Studio içinden yürütme planını göstererek bunu doğrulayabilirsiniz. Hesaplanan her alan belirtilir Exprxxxxx(burada xxxxx bir sayıdır). Ne arayacağınızı biliyorsanız, aynı ifadeyi kullandığını doğrulayabilmeniz gerekir.

Tartışmaya eklemek için diğer estetik seçeneğiniz ortak bir tablo ifadesidir :

with [cte] as
(
    select
        (case when a.type = 'workover' then 'workover' else 
        (case when substring(c.category, 2, 1) = 'd' then 'drilling'
              when substring(c.category, 2, 1) = 'c' then 'completion'
              when substring(c.category, 2, 1) = 'w' then 'workover'
              else 'other' end)
         end)) as [group_key],
         *
    from
        [some_table]
)
select
    [group_key],
    count(*) as [count]
from
    [cte]
group by
    [group_key]

Kısa cevap, işlevsel olarak bir görünümle aynıdır, ancak yalnızca bir sonraki ifadede kullanım için geçerlidir. Bunları çoğunlukla türetilmiş tablolara daha okunabilir bir alternatif olarak görüyorum çünkü iç içe geçmeyi önlüyor.

Bu soru ile ilgili olmasa da, kendilerine referans verebilirler ve bu şekilde tekrarlamalı sorgular oluşturmak için kullanılabilirler.


@Quick Joe Smith: Bunu da gördüğüm için Exprxxxxx konusunda haklı olduğunu düşünürdüm. Ancak, ifadeye OpType olarak el ile (case ... end) bir ad verirseniz, GROUP BY deyimindeki OpType alanını kullanırsam, bunun geçersiz bir sütun adı olduğuna dair bir hata alıyorum.
Doktor Drew

Ne yazık ki, çoğu zaman ifadeyi iki kez belirtmenin tek yolu yukarıdaki yöntemlerden birini kullanmaktır: CTE, görünüm veya iç içe sorgu.
Hızlı Joe Smith

2
CROSS UYGULAMASI hakkında da bilgi sahibi olmadığınız sürece .
Andriy M

cross applyBu durumda kullanmak biraz esnektir ve gereksiz bir kendi kendine katılım getirerek performansa zarar verebilir.
Hızlı Joe Smith

2
Öneriyi "aldığını" sanmıyorum. CROSS APPLYSadece aynı satırda sütunlarından takma tanımlar. Katılmaya gerek yok. ör.SELECT COUNT(*), hilo FROM master..spt_values CROSS APPLY (VALUES(high + low)) V(hilo) GROUP BY hilo
Martin Smith

1

Performans sadece bir yönüdür. Diğeri sürdürülebilirlik.

Şahsen, aşağıdakileri yapmaya eğilimliyim:

SELECT T.GroupingKey, SUM(T.value)
FROM
(
    SELECT 
        A.*
        (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
        (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
        END) AS GroupingKey
    FROM Table AS A
) AS T

GROUP BY T.GroupingKey

GÜNCELLEME:

İç içe yerleştirme yapmak istemiyorsanız, karmaşık ifadeleri kullanmanız gereken her tablo için GÖRÜNÜM oluşturabilirsiniz.

CREATE VIEW TableExtended
AS 
SELECT 
    A.*
    (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
    (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
    END) AS GroupingKey
FROM Table AS A

Sonra ekstra yuvalama yapmadan seçim yapabilirsiniz;

SELECT GroupingKey, SUM(value)
FROM TableExtended
GROUP BY GroupingKey
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.