Напевно, найшвидший і найпростіший спосіб надрукувати "всі прості числа (1-100)" - це повністю сприйняти той факт, що прості числа - це відомий, кінцевий і незмінний набір значень ("відомі" і "кінцеві" в межах певний діапазон, звичайно). На цьому невеликому масштабі, навіщо витрачати процесор щоразу, щоб обчислити купу значень, які були відомі дуже давно, і зайняти майже будь-яку пам'ять для зберігання?
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;
) показує, що цей запит працює краще, ніж два інші відповіді (поки що):
ХАРАКТЕРИСТИКА: 1 - 100
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 0
Dan 396 0 0
Martin 394 0 1
ВИСТАВКА: 1 - 10000
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
ПРИМІТКА . Для того, щоб запустити цей тест, мені довелося виправити помилку в коді Дана - @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, я помітив, що більше логічних показань у списку немає. Тож я повторно перевірив цей діапазон із застосованим виправленням і виявив, що логічні зчитування знову минули, а часи були трохи кращими (і так, повернулася така ж кількість рядків).
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Dan 0 179,594 180,096