it-swarm.asia

لماذا تعتبر جداول الأرقام "لا تقدر بثمن"؟

مقيمنا خبير قاعدة البيانات يخبرنا أن جداول الأرقام لا تقدر بثمن . لا أفهم لماذا. إليك جدول الأرقام:

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

في منشور المدونة ، الأساس المنطقي هو

جداول الأرقام لا تقدر بثمن حقا. أستخدمها طوال الوقت لمعالجة السلسلة ، ومحاكاة وظائف النافذة ، وملء جداول الاختبار بالكثير من البيانات ، والقضاء على منطق المؤشر ، والعديد من المهام الأخرى التي ستكون صعبة للغاية بدونها.

لكنني لا أفهم ماهية هذه الاستخدامات ، بالضبط - هل يمكنك تقديم بعض الأمثلة المقنعة والمحددة حيث يوفر لك "جدول الأرقام" الكثير من العمل في SQL Server - ولماذا يجب أن نحصل عليها؟

112
Jeff Atwood

لقد رأيت العديد من الاستخدامات عندما تحتاج إلى إسقاط "البيانات المفقودة". على سبيل المثال. لديك سلسلة زمنية (سجل وصول على سبيل المثال) وتريد إظهار عدد النتائج يوميًا خلال الثلاثين يومًا الماضية (انظر لوحة التحكم في التحليلات). إذا قمت بإجراء select count(...) from ... group by day فسوف تحصل على العدد لكل يوم ، ولكن النتيجة ستحتوي فقط على صف لكل يوم كان لديك حق وصول واحد على الأقل. من ناحية أخرى ، إذا قمت أولاً بإسقاط جدول الأيام من جدول الأرقام (select dateadd(day, -number, today) as day from numbers) ثم تركت الانضمام مع التهم (أو التطبيق الخارجي ، مهما كنت ترغب في ذلك) ، فستحصل على نتيجة لها 0 لعدد الأيام التي لم يكن لديك وصول إليها. هذا مثال واحد فقط. بالطبع ، قد يجادل المرء بأن طبقة العرض التقديمي في لوحة التحكم الخاصة بك يمكن أن تتعامل مع الأيام المفقودة وتظهر فقط 0 بدلاً من ذلك ، ولكن بعض الأدوات (على سبيل المثال SSRS) لن تكون ببساطة قادرة على التعامل مع هذا.

الأمثلة الأخرى التي رأيتها استخدمت حيل سلاسل زمنية مماثلة (تاريخ/وقت +/- رقم) للقيام بجميع أنواع حسابات النوافذ. بشكل عام ، عندما تستخدم لغة حتمية للتكرار مع عدد معروف من التكرارات ، يمكن أن تستخدم الطبيعة التصريحية والمحددة لـ SQL خدعة استنادًا إلى جدول أرقام.

راجع للشغل ، أشعر بالحاجة إلى استدعاء حقيقة أنه على الرغم من استخدام جدول الأرقام فإنه يشعر مثل التنفيذ الإجرائي الضروري ، لا تقع في مغالطة افتراضه أمر حتمي. اسمحوا لي أن أقدم مثالا على ذلك:

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

سيخرج هذا البرنامج 999999 ، وهو مضمون إلى حد كبير.

يتيح المحاولة نفسها في SQL Server ، باستخدام جدول أرقام. قم أولاً بإنشاء جدول يحتوي على مليون رقم:

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*[email protected]);
        set @j += 1;
    end
    commit;
    raiserror (N'Inserted %d*1000', 0, 0, @i)
    begin transaction;
    set @i += 1;
end
commit
go

الآن دعنا نفعل 'for loop':

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

النتيجه هي:

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

إذا كانت لديك الآن لحظة WTF (بعد كل شيء number هو المفتاح الأساسي المتجمع!) ، فإن الحيلة تسمى - مسح أمر التخصيص وأنا لم أدخل @j*[email protected] بالصدفة ... كان بإمكانك أيضًا أن تخمن وتخبر أن النتيجة هي لأن التوازي وأن أحيانًا قد تكون الإجابة الصحيحة.

هناك العديد من المتصيدون تحت هذا الجسر وقد ذكرت البعض في على دارة قصيرة عامل التشغيل المنطقي SQL Server و لا تتضمن وظائف T-SQL ترتيبًا معينًا لـ تنفيذ

82
Remus Rusanu

لقد وجدت جدول أرقام مفيدًا جدًا في مجموعة متنوعة من المواقف.

في لماذا يجب أن أفكر في استخدام جدول الأرقام المساعدة؟ ، المكتوب في عام 2004 ، أعرض بعض الأمثلة:

  • تحليل سلسلة
  • إيجاد فجوات الهوية
  • إنشاء نطاقات زمنية (على سبيل المثال ، تعبئة جدول التقويم ، والذي يمكن أن يكون ثمينًا أيضًا)
  • توليد شرائح زمنية
  • توليد نطاقات IP

في العادات السيئة للركل: استخدام الحلقات لتعبئة الجداول الكبيرة ، أُظهر كيف يمكن استخدام جدول الأرقام لإجراء عمل قصير لإدخال الكثير من الصفوف (على عكس نهج الركض في استخدام حلقة من الوقت).

في معالجة قائمة بالأعداد الصحيحة: نهجي و المزيد عن تقسيم القوائم: المحددات المخصصة ومنع التكرارات والحفاظ على الترتيب ، أشرح كيفية استخدام جدول أرقام لتقسيم سلسلة (على سبيل المثال مجموعة من القيم المفصولة بفواصل) وتقديم مقارنات للأداء بين هذه الطرق وغيرها. مزيد من المعلومات حول التجزئة ومعالجة السلاسل الأخرى:

وفي جدول أرقام SQL Server ، شرح - الجزء 1 ، أعطي بعض الخلفية حول المفهوم ولدي منشورات مستقبلية في المتجر لتفصيل تطبيقات محددة.

هناك العديد من الاستخدامات الأخرى ، تلك قليلة فقط برزت لي بما يكفي للكتابة عنها.

ومثلgbn ، لدي بعض الإجابات عن تجاوز سعة المكدس و في هذا الموقع التي تستخدم جدول أرقام أيضًا.

أخيرًا ، لدي سلسلة من مشاركات المدونات حول إنشاء مجموعات بدون حلقات ، والتي تُظهر جزئيًا ميزة الأداء في استخدام جدول الأرقام مقارنةً بمعظم الطرق الأخرى (جانبًا بعيدًا عن Remus الغريب):

56
Aaron Bertrand

إليك مثال رائع استخدمته مؤخرًا من Adam Machanic:

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 للعثور على مثيل محدد من السلسلة الفرعية (أي "البحث عن الأنبوب الثالث في هذه السلسلة") للعمل مع البيانات المحددة المرتبطة:

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))[email protected])
SELECT Number
FROM Occurrences
WHERE [email protected]

إذا لم يكن لديك جدول أرقام ، فإن البديل هو استخدام حلقة من نوع ما. بشكل أساسي ، يتيح لك جدول الأرقام إجراء التكرار المستند إلى مجموعة ، بدون مؤشرات أو حلقات.

26
JNK

سأستخدم جدول أرقام كلما احتجت إلى مكافئ SQL من Enumerable.Range. على سبيل المثال ، لقد استخدمته للتو في إجابة على هذا الموقع: حساب عدد التباديل

12
A-K