Hesaplanan Sütun Dizini Kullanılmıyor


14

İki sütun eşit olup olmadığına göre hızlı bir arama yapmak istiyorum. Bir dizin ile hesaplanan bir sütun kullanmaya çalıştım, ancak SQL Server kullanmak gibi görünmüyor. Ben sadece bir dizin ile statik olarak doldurulmuş bir bit sütunu kullanırsanız, beklenen dizin arama olsun.

Görünüşe göre bunun gibi başka sorular var, ama hiçbiri neden bir endeksin kullanılmayacağına odaklanmadı.

Test Tablosu:

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    )

create index ix_DiffPersisted on Diffs (DiffPersisted)
create index ix_DiffComp on Diffs (DiffComp)
create index ix_DiffStatic on Diffs (DiffStatic)

Ve Sorgu:

select Id from Diffs where DiffPersisted = 1
select Id from Diffs where DiffComp = 1
select Id from Diffs where DiffStatic = 1

Ve ortaya çıkan icra planları: Yürütme planı

Yanıtlar:


10

İle deneyin COALESCEyerine ISNULL. İle ISNULL, SQL Server dar bir dizine karşı bir yüklem itme gibi görünmüyor ve bu nedenle bilgileri bulmak için kümelenmiş tarama gerekir.

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    );

Bununla birlikte, statik bir sütuna sadık kalırsanız, filtrelenmiş bir dizin daha mantıklı olabilir ve daha düşük G / Ç maliyetlerine (tümü genellikle filtre yüklemiyle eşleşen kaç satıra bağlı olarak) örn.

CREATE INDEX ix_DiffStaticFiltered 
  ON dbo.Diffs(DiffStatic)
  WHERE DiffStatic = 1;

Çok ilginç, bunu düşünmezdim. COALESCEBu noktada sadece kurtulmak gibi görünüyor ; İnanıyorum CASEdeyimi zaten dönmek için garantili 0veya 1ancak ISNULLSQL Server null olmayan bir doğuracak sadece bu yüzden mevcuttu BITbilgisayarlı sütun için. Ancak COALESCEyine de boş bir sütun verecektir. Dolayısıyla bu değişikliğin, etkisi olsun olmasın tek etkisi COALESCE, hesaplanan sütunun artık geçersiz olduğu, ancak dizin aramasının kullanılabilmesidir.
Geoff Patterson

@Offeo Evet, bu doğru. Ancak bu durumda, NULL hesaplanmış sütun tanımına göre gerçekten olası bir çıktı olmadığını bildiğimizden , bu gerçekten bu tabloyu bir SELECT INTO kaynağı olarak kullanırsak önemlidir.
Aaron Bertrand

Bu inanılmaz bir bilgi - teşekkürler! Son hedefim, DataA ve DataB sütunlarının kayıtta denormalize sütunların eşzamansız güncellenmesine izin vermek için "kirli" uuids olarak kullanılmasıdır, bu nedenle Diff bayrağının 1 olduğu yerde çok fazla olmamalıdır. sonra iki uuidi izlemek ve alanı güncellemek için bir tetikleyici eklemeyi düşünüyordum.
David Faivre

Ayrıca, @GeoffPatterson'un işaret ettiği gibi, kullanamıyorum COALESCE? Neden saklayayım ki?
David Faivre

@David Muhtemelen COALESCE. Orijinal kodunuzun görünümünü ve amacını korumaya çalıştım ve onsuz test etmedim, böylece test sizin üzerinizde olacak. (Neden ISNULLilk etapta orada olduğunu açıklayamıyorum .)
Aaron Bertrand

5

Bu, en dıştaki ISNULLkullanıldığında ve sütunun veri türü olduğunda SQL Server hesaplanmış sütun eşleştirme mantığının belirli bir sınırlamasıdır bit.

Hata raporu

Sorunu önlemek için aşağıdaki geçici çözümlerden herhangi biri kullanılabilir:

  1. En dışta kullanmayın ISNULL(hesaplanmış bir sütun yapmanın tek yolu NOT NULL).
  2. bitVeri türünü, hesaplanan sütunun son türü olarak kullanmayın .
  3. Hesaplanan sütunu yapın PERSISTEDve izleme bayrağını etkinleştirin 174 .

ayrıntılar

Sorunun kalbi, izleme bayrağı 174 olmadan, bir sorgudaki tüm hesaplanmış sütun referanslarının (hatta kalıcı) sorgu derlemesinde çok erken temel tanımlara genişletilmesidir.

Genişletme fikri, yalnızca sütun adında değil, yalnızca tanım üzerinde çalışabilecek basitleştirmeleri ve yeniden yazmaları etkinleştirebilmesidir. Örneğin, sorgu referansında, hesaplanmış sütunun hesaplamanın bir kısmını gereksiz veya başka şekilde daha kısıtlı hale getirebilecek tahminler olabilir.

Erken sadeleştirmeler ve yeniden yazma işlemleri göz önüne alındığında, sorgu derleme, sorgudaki ifadeleri hesaplanan sütunlarla eşleştirmeye çalışır (tüm hesaplanmış sütunlar, yalnızca sorgu metninde orijinal olarak bulunanlar değil).

Değişmeyen hesaplanmış sütun ifadeleri, çoğu durumda sorun olmadan orijinal hesaplanmış sütuna karşılık gelir. En bitdıştaki bir tür ifadesini eşleştirmeye özgü bir hata var gibi görünüyor ISNULL. Bu özel durumda eşleşme başarısız olur, iç kısımların ayrıntılı bir incelemesi başarılı olması gerektiğini gösteriyor olsa bile.

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.