これまでで最も迅速かつ最も簡単な方法は、印刷「すべての素数(1-100)は、」完全にAの中に素数が知られているという事実は、有限、不変の値のセット(「既知」と「有限」を採用することですもちろん、特定の範囲)。この小さな規模で、非常に長い間知られている値の束を計算するために毎回CPUを浪費し、格納するメモリをほとんど消費しないのはなぜですか?
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)
もちろん、1から100までの素数を計算する必要がある場合は、次の方法がかなり効率的です。
;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
);
とにかく偶数は素数ではないため、このクエリは奇数のみをテストします。また、1〜100の範囲に固有です。
ここで、(質問のサンプルコードに示されているものと同様の)ダイナミックレンジが必要な場合、以下は、まだかなり効率的な上記のクエリの適応です(1-100,000-9592の範囲を計算しました)エントリ-1秒未満):
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
);
私のテスト(を使用SET STATISTICS TIME, IO ON;
)は、このクエリが(これまでのところ)指定された他の2つの回答よりも優れていることを示しています。
範囲:1〜100
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 0
Dan 396 0 0
Martin 394 0 1
範囲:1-10,000
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 47 170
Dan 77015 2547 2559
Martin n/a
範囲: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
範囲:99,900-100,000
注:このテストを実行するために、Danのコードのバグを修正する必要@startnum
がありました- クエリに考慮されなかったため、常にで開始されました1
。Dividend.num <= @endnum
行をに置き換えましたDividend.num BETWEEN @startnum AND @endnum
。
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 1
Dan 0 157 158
Martin n/a
範囲:1〜100,000(部分的な再テスト)
99,900〜100,000のテストに対するDanのクエリを修正した後、論理的な読み取りがリストされていないことに気付きました。したがって、この修正を適用したままこの範囲を再テストしたところ、論理読み取りが再びなくなり、時間がわずかに改善されたことがわかりました(そして、はい、同じ数の行が返されました)。
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Dan 0 179,594 180,096