Oracle-要素数


需要:200 w以内の素数の素数を求めるのは1と自身の整除することしかできない数で、1は素数ではありません
一.SQL版
まず2 wでテストします
--   1   ,      ,  not exists    
WITH t AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
t1 AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1)
SELECT count(*)
  FROM t
 WHERE NOT EXISTS (SELECT t1.rn
          FROM t1
         WHERE t1.rn != t.rn
           AND MOD(t.rn, t1.rn) = 0);


--               
WITH t AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
t1 AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1)
SELECT count(*)
  FROM t
 WHERE NOT EXISTS (SELECT t1.rn
          FROM t1
         WHERE t1.rn < t.rn
           AND MOD(t.rn, t1.rn) = 0);



--                     ,  t1         
-- where              
WITH t AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
t1 AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= sqrt(20000-1)
SELECT count(*)
  FROM t
 WHERE NOT EXISTS (SELECT t1.rn
          FROM t1
         WHERE t1.rn <= sqrt(t.rn)
           AND MOD(t.rn, t1.rn) = 0);

実行レコード:
scoot@orcl>--   1   ,      ,  not exists   
scoot@orcl>WITH t AS
  2   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
  3  t1 AS
  4   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1)
  5  SELECT count(*)
  6    FROM t
  7   WHERE NOT EXISTS (SELECT t1.rn
  8            FROM t1
  9           WHERE t1.rn != t.rn
 10             AND MOD(t.rn, t1.rn) = 0);

  COUNT(*)
----------
      2262

    :  00: 00: 32.19
scoot@orcl>
scoot@orcl>
scoot@orcl>--               
scoot@orcl>WITH t AS
  2   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
  3  t1 AS
  4   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1)
  5  SELECT count(*)
  6    FROM t
  7   WHERE NOT EXISTS (SELECT t1.rn
  8            FROM t1
  9           WHERE t1.rn < t.rn
 10             AND MOD(t.rn, t1.rn) = 0);

  COUNT(*)
----------
      2262

    :  00: 00: 24.42
scoot@orcl>
scoot@orcl>
scoot@orcl>--                   ,  t1         
scoot@orcl>-- where              
scoot@orcl>WITH t AS
  2   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 20000 -1),
  3  t1 AS
  4   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= sqrt(20000-1)
  5  SELECT count(*)
  6    FROM t
  7   WHERE NOT EXISTS (SELECT t1.rn
  8            FROM t1
  9           WHERE t1.rn <= sqrt(t.rn)
 10             AND MOD(t.rn, t1.rn) = 0);

  COUNT(*)
----------
      2262

    :  00: 00: 00.57
scoot@orcl>

簡単な論理的な最適化により、CPUは32秒から0.57秒に多くの不要なデータ計算時間を計算することが少なくなり、性能が大幅に向上した.
2 wを200 wに調整
--         2w   200w
WITH t AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 2000000 -1),
t1 AS
 (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= sqrt(2000000-1)
SELECT count(*)
  FROM t
 WHERE NOT EXISTS (SELECT t1.rn
          FROM t1
         WHERE t1.rn <= sqrt(t.rn)
           AND MOD(t.rn, t1.rn) = 0);
           
--           ,    
--       ,  minus,  2      20w  ,     
--         2     
WITH t AS (
   SELECT ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1
   )
,t_prime AS (
   SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1
   UNION ALL
   SELECT 2 FROM DUAL
   )
SELECT COUNT(*)
  FROM (SELECT rn from t_prime
        MINUS
        SELECT t1.rn * t2.rn
          FROM t t1, t t2
         WHERE t1.rn <= t2.rn
               AND t1.rn <= (SELECT SQRT(2000000) FROM DUAL)
               AND t1.rn * t2.rn <2000000
       );
 
--     ,  3 、5、7             
WITH t0 AS
 (SELECT 2*rownum+1 rn FROM dual  CONNECT BY rownum <= 1000000 -1),
t AS
 (select rn from t0 where mod(rn,3) != 0 and  mod(rn,5) != 0 and mod(rn,7) != 0 )
SELECT COUNT(*)+1+3 --2,3,5,7
   FROM (SELECT rn from t
         MINUS
         SELECT t1.rn * t2.rn
           FROM t t1, t t2
         WHERE t1.rn <= t2.rn
               AND t1.rn BETWEEN 9 AND (SELECT SQRT(2000000) FROM DUAL)
               AND t1.rn * t2.rn <2000000
       );
--        
WITH t0 AS (
    SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1-1
    ),
t as(SELECT rn from t0 
      where mod(rn,3)<>0 
            and mod(rn,5)<>0 
            and mod(rn,7)<>0 
            and mod(rn,11)<>0 
            and mod(rn,13)<>0
            and mod(rn,17)<>0
            and mod(rn,19)<>0
            and mod(rn,23)<>0
            and mod(rn,29)<>0
    )
SELECT COUNT(*)+10 --2,3,5,7,11,13,17,19,23,29
   FROM (SELECT rn from t
         MINUS
         SELECT t1.rn * t2.rn
           FROM t t1, t t2
         WHERE t1.rn <= t2.rn
               AND t1.rn BETWEEN 31 AND (SELECT SQRT(2000000) FROM DUAL)
               AND t1.rn * t2.rn <2000000
       );

実行レコード
scoot@orcl>--         2w   200w
scoot@orcl>WITH t AS
  2   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= 2000000 -1),
  3  t1 AS
  4   (SELECT rownum+1 rn FROM dual CONNECT BY rownum <= sqrt(2000000-1)
  5  SELECT count(*)
  6    FROM t
  7   WHERE NOT EXISTS (SELECT t1.rn
  8            FROM t1
  9           WHERE t1.rn <= sqrt(t.rn)
 10             AND MOD(t.rn, t1.rn) = 0);

  COUNT(*)
----------
    148933

    :  00: 04: 13.83
scoot@orcl>--              
scoot@orcl>--       ,  minus,  2      20w  ,     
scoot@orcl>--         2     
scoot@orcl>WITH t AS (
  2     SELECT ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1
  3     )
  4  ,t_prime AS (
  5     SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1
  6     UNION ALL
  7     SELECT 2 FROM DUAL
  8     )
  9  SELECT COUNT(*)
 10    FROM (SELECT rn from t_prime
 11          MINUS
 12          SELECT t1.rn * t2.rn
 13            FROM t t1, t t2
 14           WHERE t1.rn <= t2.rn
 15                 AND t1.rn <= (SELECT SQRT(2000000) FROM DUAL)
 16                 AND t1.rn * t2.rn <2000000
 17         );

  COUNT(*)
----------
    148933

    :  00: 02: 04.74
scoot@orcl>
scoot@orcl>
scoot@orcl>
scoot@orcl>
scoot@orcl>--     ,  3 、5、7    
scoot@orcl>WITH t0 AS
  2   (SELECT 2*rownum+1 rn FROM dual  CONNECT BY rownum <= 1000000 -1),
  3  t AS
  4   (select rn from t0 where mod(rn,3) != 0 and  mod(rn,5) != 0 and mod(rn,7) != 0 )
  5  SELECT COUNT(*)+1+3 --2,3,5,7
  6     FROM (SELECT rn from t
  7           MINUS
  8           SELECT t1.rn * t2.rn
  9             FROM t t1, t t2
 10           WHERE t1.rn <= t2.rn
 11                 AND t1.rn BETWEEN 9 AND (SELECT SQRT(2000000) FROM DUAL)
 12                 AND t1.rn * t2.rn <2000000
 13         );

COUNT(*)+1+3--2,3,5,7
------------------------
                  148933

    :  00: 00: 14.23

scott@orcl>WITH t0 AS (
  2      SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (2000000)/2-1-1
  3      ),
  4  t as(SELECT rn from t0
  5        where mod(rn,3)<>0
  6              and mod(rn,5)<>0
  7              and mod(rn,7)<>0
  8              and mod(rn,11)<>0
  9              and mod(rn,13)<>0
 10              and mod(rn,17)<>0
 11              and mod(rn,19)<>0
 12              and mod(rn,23)<>0
 13              and mod(rn,29)<>0
 14      )
 15  SELECT COUNT(*)+10 --2,3,5,7,11,13,17,19,23,29
 16     FROM (SELECT rn from t
 17           MINUS
 18           SELECT t1.rn * t2.rn
 19             FROM t t1, t t2
 20           WHERE t1.rn <= t2.rn
 21                 AND t1.rn BETWEEN 31 AND (SELECT SQRT(2000000) FROM DUAL)
 22                 AND t1.rn * t2.rn <2000000
 23         )
 24  /

COUNT(*)+10--2,3,5,7,11,13,17,19,23,29
--------------------------------------
                                148933

    :  00: 00: 08.13

実行時間は4分13秒から8.13秒に最適化され、パフォーマンスが大幅に向上しました.