Decode360's Blog

          業精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
            397 隨筆 :: 33 文章 :: 29 評論 :: 0 Trackbacks
          用SQL計算100以內的質數
          ?
          ??? 蠻有意思的一段SQL,拿來看一下。
          ?

          ===========================================================
          作者: yangtingkun(
          http://yangtingkun.itpub.net )
          發表于: 2008.01.07 23:23
          分類: ORACLE
          出處:
          http://yangtingkun.itpub.net/post/468/450278
          -----------------------------------------------------------
          ?
          ??? 以前寫過一篇文章,描述如何使用PL/SQL來計算100以內的質數,今天重翻那篇文章的時候,突然想到,能不能用SQL來實現同樣的功能。
          ?
          ??? PLSQL計算質數: http://yangtingkun.itpub.net/post/468/53770
          ?
          ?
          ?
          ?
          ??? 其實這個功能用PLSQL實現最簡單,思路也很清晰,判斷一個數是否是質數,只需要檢查這個數能否被比它小的質數整除就可以了。但是這種操作通過SQL來實現就十分的困難,因此這里通過另外一種方式來實現這個功能——構造。
          ?
          通過查詢100以內的數,去掉所有的合數,剩下的就是質數了:
          ?
          SQL> WITH T
          ? 2 AS
          ? 3 (SELECT ROWNUM RN FROM DUAL CONNECT BY LEVEL < 100)
          ? 4 SELECT RN FROM T
          ? 5 WHERE RN > 1
          ? 6 MINUS
          ? 7 SELECT A.RN * B.RN FROM T A, T B
          ? 8 WHERE A.RN <= B.RN
          ? 9 AND A.RN > 1
          ?10 AND B.RN > 1;
          ?
          ??????? RN
          ----------
          ???????? 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
          ?
          25 rows selected.
          ?
          ?
          ?
          但是這種方法的效率明顯要比PL/SQL的效率要低,如果取10000以內的質數:
          ?
          ?
          SQL> SET TIMING ON
          SQL> SET AUTOT TRACE STAT
          SQL> WITH T
          ? 2 AS
          ? 3 (SELECT ROWNUM RN FROM DUAL CONNECT BY LEVEL < 10000)
          ? 4 SELECT RN FROM T
          ? 5 WHERE RN > 1
          ? 6MINUS
          ? 7 SELECT A.RN * B.RN FROM T A, T B
          ? 8 WHERE A.RN <= B.RN
          ? 9 AND A.RN > 1
          ?10AND B.RN > 1;
          ?
          1229 rows selected.
          ?
          Elapsed: 00:02:41.54
          ?
          Statistics
          ----------------------------------------------------------
          ??????? 511 recursive calls
          ???????? 81 db block gets
          ???? 180002 consistent gets
          ????? 65131 physical reads
          ??????? 648 redo size
          ????? 17139 bytes sent via SQL*Net to client
          ?????? 1276 bytes received via SQL*Net from client
          ???????? 83 SQL*Net roundtrips to/from client
          ????????? 2 sorts (memory)
          ????????? 1 sorts (disk)
          ?????? 1229 rows processed
          ?
          ?
          這個SQL執行了2分半種以上,當然這個SQL還可以進行一下優化,比如A的取值可以小于10000的開方,而B的取值可以小于10000除以最小的質數:
          ?
          ?
          SQL> WITH T
          ? 2 AS
          ? 3 (SELECT ROWNUM RN FROM DUAL CONNECT BY LEVEL < 10000)
          ? 4 SELECT RN FROM T
          ? 5 WHERE RN > 1
          ? 6 MINUS
          ? 7 SELECT A.RN * B.RN FROM T A, T B
          ? 8 WHERE A.RN <= B.RN
          ? 9AND A.RN > 1
          ?10 AND A.RN <= 100
          ?11 AND B.RN > 1
          ?12 AND B.RN <= 5000;
          ?
          1229 rows selected.
          ?
          Elapsed: 00:00:00.78
          ?
          Statistics
          ----------------------------------------------------------
          ????????? 2 recursive calls
          ???????? 23 db block gets
          ?????? 1820 consistent gets
          ???????? 16 physical reads
          ??????? 692 redo size
          ????? 17139 bytes sent via SQL*Net to client
          ?????? 1276 bytes received via SQL*Net from client
          ???????? 83 SQL*Net roundtrips to/from client
          ????????? 3 sorts (memory)
          ????????? 0 sorts (disk)
          ?????? 1229 rows processed
          ?
          ?
          優化后,SQL的執行效率提高了3個數量級,其實這個SQL仍然是可以優化的,考慮除了2以外,所有的質數均為奇數:
          ?
          ?
          SQL> WITH T
          ? 2 AS
          ? 3 (SELECT ROWNUM * 2 + 1 RN FROM DUAL CONNECT BY LEVEL < 4999)
          ? 4 SELECT 2 FROM DUAL
          ? 5 UNION ALL
          ? 6 (
          ? 7 SELECT RN FROM T
          ? 8 WHERE RN > 1
          ? 9 MINUS
          ?10 SELECT A.RN * B.RN FROM T A, T B
          ?11 WHERE A.RN <= B.RN
          ?12 AND A.RN > 1
          ?13 AND A.RN <= 100
          ?14 AND B.RN > 1
          ?15 AND B.RN <= 5000
          ?16 )
          ?17 ;
          ?
          1229 rows selected.
          ?
          Elapsed: 00:00:00.25
          ?
          Statistics
          ----------------------------------------------------------
          ????????? 2 recursive calls
          ???????? 15 db block gets
          ??????? 512 consistent gets
          ????????? 8 physical reads
          ??????? 648 redo size
          ????? 17138 bytes sent via SQL*Net to client
          ?????? 1276 bytes received via SQL*Net from client
          ???????? 83 SQL*Net roundtrips to/from client
          ????????? 3 sorts (memory)
          ????????? 0 sorts (disk)
          ?????? 1229 rows processed
          ?
          雖然通過SQL優化已經將極大的提高了效率,但是和PLSQL比,效率仍然相去甚遠:
          ?
          ?
          ?
          SQL> DECLARE
          ? 2 TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
          ? 3 V_RESULT T_RECORD;
          ? 4 I NUMBER DEFAULT 3;
          ? 5 N NUMBER DEFAULT 0;
          ? 6 BEGIN
          ? 7 --DBMS_OUTPUT.PUT_LINE(2);
          ? 8 V_RESULT(1) := 3;
          ? 9 WHILE(I < 10000) LOOP
          ?10 FOR J IN 1..V_RESULT.COUNT LOOP
          ?11 IF V_RESULT(J) * V_RESULT(J) > I THEN
          ?12 --DBMS_OUTPUT.PUT_LINE(I);
          ?13 V_RESULT(V_RESULT.COUNT + 1) := I;
          ?14 EXIT;
          ?15 END IF;
          ?16 IF TRUNC(I/V_RESULT(J)) = I/V_RESULT(J) THEN
          ?17 EXIT;
          ?18END IF;
          ?19 END LOOP;
          ?20 IF N = 2 THEN
          ?21 I := I + 4;
          ?22 N := 1;
          ?23 ELSE
          ?24 I := I + 2;
          ?25 N := N + 1;
          ?26 END IF;
          ?27 END LOOP;
          ?28 V_RESULT(0) := 2;
          ?29 END;
          ?30 /
          ?
          PL/SQL procedure successfully completed.
          ?
          Elapsed: 00:00:00.04
          ?
          這說明使用SQL并不一定就是最佳選擇,有的時候使用PLSQL效率反而會更高。使用合適的方法做適合的事情,一味追求使用單條SQL實現很可能會損失性能。
          ?

          ?
          posted on 2008-12-27 21:31 decode360 閱讀(352) 評論(0)  編輯  收藏 所屬分類: 05.SQL
          主站蜘蛛池模板: 修武县| 古交市| 舞阳县| 曲周县| 嘉定区| 封开县| 包头市| 南靖县| 永德县| 福泉市| 天等县| 元氏县| 青冈县| 博湖县| 称多县| 平武县| 宣恩县| 淳安县| 苗栗市| 湖南省| 海宁市| 新龙县| 吉林省| 永善县| 新巴尔虎左旗| 伊宁县| 桦南县| 南溪县| 新河县| 远安县| 茌平县| 广南县| 股票| 邵武市| 株洲市| 陆川县| 石屏县| 翁源县| 贵港市| 聊城市| 保德县|