Sayı tabloları neden “paha biçilmez”?


112

Yerleşik veritabanı uzmanımız , sayı tablolarının paha biçilmez olduğunu söylüyor . Nedenini tam olarak anlamadım. İşte bir sayı tablosu:

USE Model
GO

CREATE TABLE Numbers
(
    Number INT NOT NULL,
    CONSTRAINT PK_Numbers 
        PRIMARY KEY CLUSTERED (Number)
        WITH FILLFACTOR = 100
)

INSERT INTO Numbers
SELECT
    (a.Number * 256) + b.Number AS Number
FROM 
    (
        SELECT number
        FROM master..spt_values
        WHERE 
            type = 'P'
            AND number <= 255
    ) a (Number),
    (
        SELECT number
        FROM master..spt_values
        WHERE 
            type = 'P'
            AND number <= 255
    ) b (Number)
GO

Blog yazısı başına verilen mantık

Sayı tabloları gerçekten paha biçilmezdir. Bunları her zaman dize manipülasyonu, pencere fonksiyonlarını simüle etme, test tablolarını çok sayıda veri ile doldurma, imleç mantığını ortadan kaldırma ve onlarsız inanılmaz zor olabilecek diğer birçok görev için kullanıyorum.

Ancak bu kullanımların ne anlama geldiğini tam olarak anlamadım - bir "sayı tablosunun" sizi SQL Server'da bir ton işden kurtardığı ve buna neden sahip olmalıyız?


3
Sayılar tablosu için birçok kullanım durumu, anında ihtiyacınız olan sayıları üreten özyinelemeli bir CTE tarafından aynı şekilde karşılanabilir. Bununla birlikte, performans cezası ve CTE yaklaşımındaki diğer bazı sınırlamalar vardır .
Nick Chammas

4
@Nick: Fiziksel bir tabloya karşılık anında bir CTE tabanlı sayı tablosunun sayı tablosunu nasıl oluşturduğunuzun sadece bir uygulama detayı olduğunu söyleyebilirim . Patates vs. Patates ...
Remus Rusanu

1
@Remus - Yup. Sadece bu alternatifi Jeff'e işaret etmek istedim.
Nick Chammas

2
SO stackoverflow.com/search?q=user%3A27535+%2B%22numbers+table%22 adresindeki bir sayı tablosunu kullanarak bir düzine yanıtım var .
Ocak'ta

Yanıtlar:


82

'Eksik verileri' yansıtmanız gerektiğinde birçok kullanım gördüm. Örneğin. Bir zaman seriniz var (örneğin bir erişim günlüğü) ve son 30 gün boyunca günde isabet sayısını göstermek istiyorsunuz (analitik kontrol panelini düşünün). Bunu yaparsanız select count(...) from ... group by day, her gün için sayımı elde edersiniz, ancak sonuçta yalnızca en az bir erişiminiz olan her gün için bir satır bulunur. Öte yandan, ilk önce sayılar tablonuzdan ( select dateadd(day, -number, today) as day from numbers) sonra bir gün tablosu yansıtırsanız ve sonra sayımlarla (veya dış başvurunuz, ne isterseniz) katılırsanız, o zaman sayınız için 0 olan bir sonuç alırsınız. erişimi yoktu. Bu sadece bir örnek. Tabii ki, gösterge tablonuzun sunum katmanının eksik günleri idare edebileceğini ve sadece 0 gösterebileceğini iddia edebilir, ancak bazı araçlar (örn. SSRS) bunu kaldıramaz.

Gördüğüm diğer örnekler, tüm pencere hesaplamalarını yapmak için benzer zaman serileri (tarih / saat +/- numarası) kullandı. Genel olarak, ne zaman zorunlu bir dilde iyi bilinen sayıda yinelemeye sahip bir for döngüsü kullanacaksanız, SQL'in bildirimsel ve ayarlanmış niteliği bir sayı tablosuna dayalı bir numara kullanabilir.

BTW, bir sayı tablosu kullanmakla birlikte , zorunlu işlem yürütme gibi hissettirse de , zorunlu olduğunu varsayma yanılsamasına düşmediği gerçeğini söylememe gerek olduğunu hissediyorum . Bir örnek vereyim:

int x;
for (int i=0;i<1000000;++i)
  x = i;
printf("%d",x);

Bu program 999999'u yayınlayacaktır, ki bu neredeyse garantilidir.

Bir sayı tablosu kullanarak, SQL Server'da aynı deneyelim. İlk önce 1.000.000 kişilik bir tablo oluşturun:

create table numbers (number int not null primary key);
go

declare @i int = 0
    , @j int = 0;

set nocount on;
begin transaction
while @i < 1000
begin
    set @j = 0;
    while @j < 1000
    begin
        insert into numbers (number) 
            values (@j*1000+@i);
        set @j += 1;
    end
    commit;
    raiserror (N'Inserted %d*1000', 0, 0, @i)
    begin transaction;
    set @i += 1;
end
commit
go

Şimdi 'for loop' yapalım:

declare @x int;
select @x = number 
from numbers with(nolock);
select @x as [@x];

Sonuç:

@x
-----------
88698

(Sonuçta artık bir WTF anı yaşıyorsanız number olan kümelenmiş birincil anahtar!), Hüner denir tahsisi düzeni taramak ve ben eklemek vermedi @j*1000+@ikaza ... Ayrıca vardı bir tahmin girişim ve sonuç çünkü söyleyebiliriz paralellik ve bazen olabilir doğru cevap olsun.

Bu köprünün altında pek çok trol var ve bazı SQL Server boolean operatöründe kısa devre olduğundan bahsetmiştim ve T-SQL işlevleri belirli bir işlem sırası anlamına gelmiyor


55

Çeşitli durumlarda oldukça yararlı bir sayı tablosu buldum.

At Neden bir yardımcı sayılar tablosu kullanılarak düşünmelisiniz? , 2004 yılında yazılmış, birkaç örnek göstereceğim:

  • Bir dize ayrıştırma
  • Kimlik açığı bulma
  • Tarih aralıkları oluşturma (örneğin, paha biçilmez olabilen bir takvim tablosu doldurma)
  • Zaman dilimleri oluşturma
  • IP aralıkları oluşturma

At tekme Kötü alışkanlıkları: büyük tablolarını doldurmak için döngüler kullanarak , bir sayı tablosu (a while döngüsü kullanmak diz refleksi yaklaşım aksine) sıralar bir çok ekleme kısa çalışması için nasıl kullanılabileceğini göstermektedir.

Bir tamsayı listesi işlerken: yaklaşımım ve Daha fazla bilgi bölme listelerinde: özel sınırlayıcılar, yinelemeleri önleme ve düzeni sağlamada , bir dize (örneğin virgülle ayrılmış değerler kümesi) bölmek ve performans sağlamak için bir sayı tablosunun nasıl kullanılacağını gösteririm. Bu ve diğer yöntemler arasındaki karşılaştırmalar. Bölme ve dize işleme hakkında daha fazla bilgi:

Ve SQL Server Sayılar Tablosunda, Anlatılan - Bölüm 1 , konsept hakkında biraz bilgi verdim ve belirli uygulamaları ayrıntılı olarak saklamak için gelecekteki görevlerim var.

Başka birçok kullanım var, bunlar hakkında yazacak kadar bana dikkat çeken birkaçı.

Ve gbn gibi , yığın taşması ve aynı zamanda bir sayı tablosu kullanan bu sitede birkaç cevabım var .

Son olarak, döngüsel olmayan kümeler oluşturma hakkında bir dizi blog yazısına sahibim; bu, diğer pek çok yönteme kıyasla bir sayı tablosu kullanmanın performans avantajını göstermektedir (Remus 'ilginç bir kenara çeker):


26

İşte son zamanlarda Adam Machanic’ten kullandığım harika bir örnek :

CREATE FUNCTION dbo.GetSubstringCount
(
    @InputString TEXT, 
    @SubString VARCHAR(200),
    @NoisePattern VARCHAR(20)
)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    RETURN 
    (
        SELECT COUNT(*)
        FROM dbo.Numbers N
        WHERE
            SUBSTRING(@InputString, N.Number, LEN(@SubString)) = @SubString
            AND PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number + LEN(@SubString), 1)) = 0
            AND 0 = 
                CASE 
                    WHEN @NoisePattern = '' THEN 0
                    ELSE PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number - 1, 1))
                END
    )
END

CTEİlişkili sınırlandırılmış verilerle çalışmak için a ile benzer bir şey daha kullandım.

declare @TargetStr varchar(8000), 
@SearchedStr varchar(8000), 
@Occurrence int
set @TargetStr='a'
set @SearchedStr='abbabba'
set @Occurrence=3;

WITH Occurrences AS (
SELECT Number,
       ROW_NUMBER() OVER(ORDER BY Number) AS Occurrence
FROM master.dbo.spt_values
WHERE Number BETWEEN 1 AND LEN(@SearchedStr) AND type='P'
  AND SUBSTRING(@SearchedStr,Number,LEN(@TargetStr))=@TargetStr)
SELECT Number
FROM Occurrences
WHERE Occurrence=@Occurrence

Bir sayı tablonuz yoksa, alternatif bir tür döngü kullanmaktır. Temel olarak, bir sayılar tablosu, imleçler veya döngüler olmadan küme temelli yineleme yapmanızı sağlar.


5
Ve satır içi TVFs işi dize manipülasyon gizlenen tehlike hakkında zorunlu uyarı: T-SQL fonksiyonları hiçbir yürütme belli sıralaması anlamına do
Remus Rusanu

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.