işlevi boş durum işlemiyle kilitleniyor


9

Başlangıç ​​ve bitiş tarihini kabul eden bir işlev oluşturdum, bitiş tarihi isteğe bağlı. Daha sonra CASEbitiş tarihi geçmediyse başlangıç ​​tarihini kullanmak için filtreye bir yazdım .

CASE WHEN @dateEnd IS NULL
    THEN @dateStart
    ELSE @dateEnd
END

Verilerin en son ayı için işlevi çağırdığımda:

SELECT * FROM theFunction ('2013-06-01', NULL)

... sorgu askıda kalıyor. Bitiş tarihini belirtirsem:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')

... sonuç normal olarak döndürülür. Kod işlev dışına aldı ve bir sorgu penceresinin içinde güzel koştu. Ben de keman sorunu çoğaltamam. Şunun gibi bir sorgu:

SELECT * FROM theFunction ('2013-04-01', '2013-06-01')

... iyi çalışıyor.

Sorguda (aşağıda) NULLbitiş tarihi için a iletildiğinde işlevin askıda kalmasına neden olabilecek herhangi bir şey var mı ?

SQL Keman


Daha fazla mantık gönderebilir misiniz? Orada sahip olduğunuz şey bir soruna neden olmamalıdır.
Kenneth Fisher

3
Eğer değiştirirseniz CASEile COALESCE(@dateEnd,@dateStart)sorun hâlâ görünüyor?
ypercubeᵀᴹ

2
Peki ISNULL()?
ypercubeᵀᴹ

3
Meşgul mü yoksa bir şey mi bekliyor? "Asılır" iken ne SELECT task_state FROM sys.dm_os_tasks WHERE session_id = x gösterir? Durumda çok fazla zaman harcıyorsa RUNNING, o oturum hangi bekleme türlerine giriyor sys.dm_os_waiting_tasks?
Martin Smith

1
@ypercube ile gelişme yok COALESCE. ISNULLonu düzeltti.
Kermit

Yanıtlar:


7

İlk sorgunuzun bir kısmı aşağıdaki gibidir.

  FROM   [dbo].[calendar] a
          LEFT JOIN [dbo].[colleagueList] b
            ON b.[Date] = a.d
   WHERE  DAY(a.[d]) = 1
          AND a.[d] BETWEEN @dateStart AND COALESCE(@dateEnd,@dateStart) 

Planın bu bölümü aşağıda gösterilmiştir

resim açıklamasını buraya girin

Gözden geçirilmiş sorgunuzda BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)aynı birleştirme için buna sahip

resim açıklamasını buraya girin

Aradaki fark ISNULLdaha da basitleşiyor ve sonuç olarak bir sonraki katılımda daha doğru kardinalite istatistikleri elde ediyorsunuz. Bu satır içi tablo değerli bir işlevdir ve bunu değişmez değerlerle çağırırsınız, böylece böyle bir şey yapabilir.

 a.[d] BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart) 
 a.[d] BETWEEN '2013-06-01' AND ISNULL(NULL,'2013-06-01') 
 a.[d] BETWEEN '2013-06-01' AND '2013-06-01'
 a.[d] = '2013-06-01'

Ve bir equi birleştirme yüklemi olduğu b.[Date] = a.diçin, plan aynı zamanda bir eşitlik yüklemini de gösterir b.[Date] = '2013-06-01'. Sonuç olarak, 28,393satırların kardinalite tahmini oldukça doğru olacaktır.

İçin CASE/ COALESCEsürümü ne zaman @dateStartve @dateEnddaha sonra aynı değeri aynı eşitlik ifade kolaylaştırır.Sizlere Tamam ve aynı planı verir ama ne zaman @dateStart = '2013-06-01've @dateEnd IS NULLsadece kadarıyla gider

a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END

zımni bir yüklem olarak da uygulanır ColleagueList. Bu sefer tahmini satır sayısı 79.8satırdır.

Bir sonraki birleşim

   LEFT JOIN colleagueTime
     ON colleagueTime.TC_DATE = colleagueList.Date
        AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10)) 

colleagueTime3,249,590(tekrar) görünüşte yararlı dizinleri olmayan bir yığın olan bir satır tablosudur.

Tahminlerdeki bu tutarsızlık, kullanılan birleştirme seçimini etkiler. ISNULLPlan karma sadece bir kez tablosunu tarar olduğunu katılmak seçer. COALESCEPlan hala sadece bir kez tabloyu taramak ve 78 kez sonuç biriktirmek ve onu tekrar edebilmek için ihtiyaç duyacağı yuvalanmış döngüler katılmak seçer ve tahminleri. yani, ilişkili parametrelerin değişmeyeceğini tahmin eder.

İç içe döngüler planının iki saat sonra hala devam ettiği gerçeğinden, bu tek bir tarama varsayımı colleagueTimebüyük olasılıkla yanlış görünüyor.

Neden iki birleşme arasındaki tahmini satır sayısının çok daha düşük olduğu konusunda, tablolardaki istatistikleri görmeden emin değilim. Testlerimde çok fazla satır eklemeyi hesapladığım tahmini satır sayılarını çarpıtmanın tek yolu NULL(döndürülen gerçek satır sayısı aynı kalsa bile bu, tahmini satır sayısını azalttı).

COALESCETest verilerimle birlikte plandaki tahmini satır sayısı

number of rows matching >= condition * 30% * (proportion of rows in the table not null)

Veya SQL'de

SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
                                                  WHEN [Date] >= '2013-06-01' THEN 1
                                                END) * 0.30 )
FROM   [dbo].[colleagueList] 

ancak bu, sütunun NULLdeğer içermediği yorumunuzla kareye düşmez.


"o tablodaki Tarih sütununda NULL değerlerinin çok yüksek bir oranına sahip misiniz?" NULLBu tabloların hiçbirinde tarihler için değer yok .
Kermit

@FreshPrinceOfSO - Yazık oldu. O zaman iki tahminde neden bu kadar büyük bir tutarsızlık olduğu konusunda hala bir fikrim yok. Testlerde bitmap filtresini yaptım ve ek yüklem, belki burada yaptığı kardinalite tahminlerini değiştirmedi.
Martin Smith

@FreshPrinceOfSO - Eğer istatistikleri betimlemek istiyorsanız , bunu deneyebilirim.
Martin Smith

2008R2'deyim; Ben gidince Şemaları seç , dbolistede yok. Sadece kullanmadığım diğer şemalar.
Kermit

4

Veri türleriyle ilgili bir sorun varmış gibi görünüyor. ISNULLsorunu düzeltti (teşekkürler ypercube ). Biraz araştırma sonra COALESCEeşdeğerdir için CASEben kullanıyordum o deyimi:

CASE
   WHEN (expression1 IS NOT NULL) THEN expression1
   WHEN (expression2 IS NOT NULL) THEN expression2
   ...
   ELSE expressionN
END

Paul White şöyle açıklıyor :

COALESCE( expression [ ,...n ] ) en yüksek veri türü önceliğine sahip ifadenin veri türünü döndürür.

ISNULL(check_expression, replacement_value) check_expression ile aynı türü döndürür.

Herhangi bir veri türü sorununu önlemek ISNULLiçin, sadece iki ifadeyle uğraşmak için kullanılacak uygun fonksiyon olduğu görülüyor .

XML Planı Alıntıları

XML planı kullanarak CASE, ifade 2 NULL:

SELECT * FROM theFunction ('2013-06-01', NULL)
<ScalarOperator ScalarString="CASE WHEN (1) THEN '2013-06-01' ELSE NULL END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Const ConstValue="(1)"/>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="'2013-06-01'"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

XML planı kullanarak CASE, ifade 2 bir tarihtir:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
      </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

XML planı kullanarak ISNULL, ifade 2 NULL:

SELECT * FROM theFunction ('2013-06-01', NULL)
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

XML planı kullanarak ISNULL, ifade 2 bir tarihtir:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

Ama bu neden işe yaradığını açıklamıyor SELECT * FROM theFunction ('2013-06-01', '2013-06-01'). Veri tipi ifadesi hala aynıdır. Her iki parametre de dateveri tipidir. İcra planlarını görebilir misiniz?
Martin Smith

@MartinSmith Sonuç döndüren sorgunun planı aşağıdadır . İkinci ifade olduğunda bir planım yok NULL.
Kermit

İfadelerin içinde döküm yapmanın CASEda bir etkisi olmadı, sorgu hala askıda.
Kermit

2
İkinci dava için nasıl plan yok? Sadece sorgu asla bitmediği için mi? Öyleyse tahmini bir plan alabilir misiniz? Farklı ifadelerin kardinalite tahminlerini değiştirip değiştirmediğini ve farklı bir planla sonuçlandığını merak ediyorum.
Martin Smith

3
ISNULLBöyle bir plan görünüyor iyi kolaylaştırır. ColleagueList'te basit bir eşitlik yüklemine [Date]='2013-06-01'sahipken, CASEbunun bir yüklemi vardır [Date]>='2013-06-01' AND [Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END AND PROBE([Bitmap1067],[Date]). Bu birleştirmeden çıkan tahmini satırlar ISNULLsürüm için 28.393, ancak planın ilerleyen bölümlerinde birleştirme seçimini etkileyen sürüm 79.8için çok daha düşüktür CASE. Neden böyle bir tutarsızlık olacağından emin değilim.
Martin Smith
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.