"Tüm asal sayıları (1-100)" yazdırmanın en hızlı ve en kolay yolu , asal sayıların bilinen bir, sonlu ve değişmeyen bir değer kümesi ("bilinen" ve "sonlu") tabii ki belirli bir aralık). Bu kadar küçük bir ölçekte, neden çok uzun zamandır bilinen bir grup değeri hesaplamak ve saklamak için neredeyse hiç bellek kullanmamak için CPU'yu her seferinde boşa harcıyorsunuz?
SELECT tmp.[Prime]
FROM (VALUES (2), (3), (5), (7), (11), (13),
(17), (19), (23), (29), (31), (37), (41),
(43), (47), (53), (59), (61), (67), (71),
(73), (79), (83), (89), (97)) tmp(Prime)
Tabii ki, 1 ile 100 arasındaki asal sayıları hesaplamanız gerekiyorsa, aşağıdakiler oldukça etkilidir:
;WITH base AS
(
SELECT tmp.dummy, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [num]
FROM (VALUES (0), (0), (0), (0), (0), (0), (0)) tmp(dummy)
), nums AS
(
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT 1)) * 2) + 1 AS [num]
FROM base b1
CROSS JOIN base b2
), divs AS
(
SELECT [num]
FROM base b3
WHERE b3.[num] > 4
AND b3.[num] % 2 <> 0
AND b3.[num] % 3 <> 0
)
SELECT given.[num] AS [Prime]
FROM (VALUES (2), (3)) given(num)
UNION ALL
SELECT n.[num] AS [Prime]
FROM nums n
WHERE n.[num] % 3 <> 0
AND NOT EXISTS (SELECT *
FROM divs d
WHERE d.[num] <> n.[num]
AND n.[num] % d.[num] = 0
);
Bu sorgu yalnızca tek sayıları test eder, çünkü çift sayılar yine de asal olmaz. Ayrıca 1 - 100 aralığına özgüdür.
Şimdi, dinamik bir aralığa ihtiyacınız varsa (sorudaki örnek kodda gösterilene benzer), aşağıdaki sorgu hala oldukça verimli olan bir uyarlamadır (1 - 100.000 - 9592 aralığını hesapladı) girişler - 1 saniyenin biraz altında):
DECLARE @RangeStart INT = 1,
@RangeEnd INT = 100000;
DECLARE @HowMany INT = CEILING((@RangeEnd - @RangeStart + 1) / 2.0);
;WITH frst AS
(
SELECT tmp.thing1
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) tmp(thing1)
), scnd AS
(
SELECT 0 AS [thing2]
FROM frst t1
CROSS JOIN frst t2
CROSS JOIN frst t3
), base AS
(
SELECT TOP( CONVERT( INT, CEILING(SQRT(@RangeEnd)) ) )
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [num]
FROM scnd s1
CROSS JOIN scnd s2
), nums AS
(
SELECT TOP (@HowMany)
(ROW_NUMBER() OVER (ORDER BY (SELECT 1)) * 2) +
(@RangeStart - 1 - (@RangeStart%2)) AS [num]
FROM base b1
CROSS JOIN base b2
), divs AS
(
SELECT [num]
FROM base b3
WHERE b3.[num] > 4
AND b3.[num] % 2 <> 0
AND b3.[num] % 3 <> 0
)
SELECT given.[num] AS [Prime]
FROM (VALUES (2), (3)) given(num)
WHERE given.[num] >= @RangeStart
UNION ALL
SELECT n.[num] AS [Prime]
FROM nums n
WHERE n.[num] BETWEEN 5 AND @RangeEnd
AND n.[num] % 3 <> 0
AND NOT EXISTS (SELECT *
FROM divs d
WHERE d.[num] <> n.[num]
AND n.[num] % d.[num] = 0
);
Testlerim (kullanarak SET STATISTICS TIME, IO ON;), bu sorgunun verilen (şimdiye kadar) diğer iki cevaptan daha iyi performans gösterdiğini gösteriyor:
ARALIK: 1-100
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 0
Dan 396 0 0
Martin 394 0 1
MENZİL: 1 - 10.000
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 47 170
Dan 77015 2547 2559
Martin n/a
ARALIK: 1-100.000
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 984 996
Dan 3,365,469 195,766 196,650
Martin n/a
MENZİL: 99.900 - 100.000
NOT : Bu testi çalıştırmak için ben Dan kodunda bir hata düzeltmek zorunda - @startnumher zaman başladı bu yüzden sorgu içine çarpanlı değildi 1. Dividend.num <= @endnumHattı ile değiştirdim Dividend.num BETWEEN @startnum AND @endnum.
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 1
Dan 0 157 158
Martin n/a
ARALIK: 1-100.000 (kısmi yeniden test)
Dan'ın 99.900 - 100.000 test sorgusunu düzelttikten sonra, listelenen daha mantıklı okuma olmadığını fark ettim. Bu aralığı hala uygulanan bu düzeltme ile tekrar test ettim ve mantıksal okumaların tekrar gittiğini ve zamanların biraz daha iyi olduğunu gördüm (ve evet, aynı sayıda satır döndürüldü).
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Dan 0 179,594 180,096