Decode360's Blog

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

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
            302 隨筆 :: 26 文章 :: 82 評論 :: 0 Trackbacks
          用SQL計算100以內的質數

          ===========================================================
          作者: 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
          ? 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;
          ?
          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
          ? 9?AND 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;
          ?18?END 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實現很可能會損失性能。
          ?

          ?




          -The End-

          posted on 2008-12-27 21:31 decode360-3 閱讀(1242) 評論(0)  編輯  收藏 所屬分類: SQL Dev
          主站蜘蛛池模板: 夏邑县| 赤峰市| 双峰县| 塘沽区| 静海县| 青海省| 晋宁县| 仁寿县| 中宁县| 江津市| 江阴市| 大同市| 安图县| 扬州市| 新余市| 会昌县| 辉县市| 永修县| 沁阳市| 虹口区| 时尚| 玉屏| 合川市| 南宁市| 华安县| 轮台县| 石门县| 伊春市| 三都| 遂昌县| 英超| 龙里县| 阿拉善右旗| 和平县| 台东县| 塔河县| 荆州市| 丹巴县| 仁寿县| 宁强县| 兴城市|