• I have tested my code against Ryan's code on SQL Server 2000 and it seems to be equally fast (with the same output).

    If the Numbers table is preconstructed, I guess my code is faster (because I need a larger Numbers table). On the other hand, if I am forced to use bigints (as Ryan does), my code will

    be a bit slower.

    I have used the following in my test:

     

    /*************** MY CODE ******************/

    set nocount on

    go

    declare @time datetime

    select @time = getdate()

    DECLARE @MaxNumber INT

    SET @MaxNumber = 5000000

    SET ROWCOUNT @MaxNumber

    select identity(int, 1, 1) as Number into #Numbers

    from syscomments c1 cross join syscomments c2 cross join syscomments c3

    SET ROWCOUNT 0

    alter table #Numbers add constraint PK_Numbers primary key clustered (Number)

    create table #Primes(prime int primary key)

    declare @i int, @limit int

    set @i = 1

    while @i*@i < @MaxNumber

    begin

      set @limit = (@i+1)*(@i+1)

      if (@i+1)*(@i+1) > @MaxNumber

        set @limit = @MaxNumber + 1

      insert into #Primes

      select n.Number

      from #Numbers n

      where

      n.Number < @limit and n.Number > @i*@i

      and not exists

      (select * from #Primes p where p.prime < @i + 1 and n.Number % p.prime = 0)

      set @i = @i + 1

    end

    --select * from #Primes

    PRINT 'Finish: ' + CAST(DATEDIFF(ms, @Time, GETDATE()) AS VARCHAR(10)) + ' ms'

    SELECT COUNT(*) AS 'Number of primes', MAX(prime) AS 'Max prime' FROM #Primes

    drop table #Primes

    go

    drop table #Numbers

    go

     

     

    /******** RYAN'S CODE************************/

     

    --Inputs

    DECLARE @MaxNumber INT

    SET @MaxNumber = 5000000

    --Preparation

    SET NOCOUNT ON

    DECLARE @Time DATETIME

    SELECT @Time = GETDATE()

    --Preparation - Numbers table

    DECLARE @SqrtMaxNumber INT

    SET @SqrtMaxNumber = SQRT(@MaxNumber)

    SET ROWCOUNT @SqrtMaxNumber

    CREATE TABLE #Numbers (i BIGINT IDENTITY(1, 1) PRIMARY KEY CLUSTERED, j BIGINT, x bit)

    INSERT INTO #Numbers (x) SELECT NULL FROM syscomments c1 CROSS JOIN syscomments c2

    SET ROWCOUNT 0

    UPDATE #Numbers SET j = i*i

    PRINT 'Checkpoint A: ' + CAST(DATEDIFF(ms, @Time, GETDATE()) AS VARCHAR(10)) + ' ms'

    --Preparation - Put candidate primes into a Primes table

    -- (integers which have an odd number of representations by certain quadratic forms)

    CREATE TABLE #Primes (i BIGINT PRIMARY KEY CLUSTERED)

    INSERT #Primes

    SELECT 2 UNION ALL SELECT 3 UNION ALL

    SELECT k FROM (

        SELECT k FROM (SELECT 4 * a.j + b.j AS k FROM #Numbers a, #Numbers b) c WHERE k <= @MaxNumber AND k % 12 IN (1, 5)

        UNION ALL

        SELECT k from (select 3 * a.j + b.j AS k FROM #Numbers a, #Numbers b) c WHERE k <= @MaxNumber AND k % 12 = 7

        UNION ALL

        SELECT k from (select 3 * a.j - b.j AS k FROM #Numbers a INNER JOIN #Numbers b ON a.i > b.i) c WHERE k <= @MaxNumber AND k % 12 = 11

    ) d GROUP BY k HAVING COUNT(*) IN (1, 3)

    PRINT 'Checkpoint B: ' + CAST(DATEDIFF(ms, @Time, GETDATE()) AS VARCHAR(10)) + ' ms'

    --Calculation - Eliminate composites by sieving

    DECLARE @i BIGINT

    SET @i = 5

    WHILE @i * @i < @MaxNumber

    BEGIN

        DELETE #Primes WHERE i > @i and i % @i = 0

        SELECT @i = min(i) FROM #Primes WHERE i > @i

    --    PRINT @i

    END

    --Show results

    PRINT 'Finish: ' + CAST(DATEDIFF(ms, @Time, GETDATE()) AS VARCHAR(10)) + ' ms'

    SELECT COUNT(*) AS 'Number of primes', MAX(i) AS 'Max prime' FROM #Primes

    --SELECT * FROM #Primes ORDER BY i

    --Tidy up

    DROP TABLE #Primes

    DROP TABLE #Numbers