发新话题
打印

DBA大师实战国产数据库系列之杨廷琨:DM6.0试用系列文章

本主题由 myth 于 2010-7-14 09:57 AM 移动

DBA大师实战国产数据库系列之杨廷琨:DM6.0试用系列文章

  作者简介:杨廷琨(网名Yangtingkun),现任海虹医药电子商务有限公司首席DBA, ITPUB论坛Oracle数据库管理版版主。2004年曾参与编写《Oracle数据库性能优化》一书,2007年被Oracle公司授予Oracle ACE称号,喜欢研究Oracle相关的技术问题,他的技术博客上积累了1500多篇Oracle相关的原创技术文章。

  前几天ITPUB的熊建国主编和我联系,希望我能参加国产数据库达梦的适用活动,并写几篇使用感受。本来最近手工的事情比较多,本打算推辞的,不过熊主编再三邀请,而且强调并非是枪手文,只要写出真实使用感受即可。既然如此,我就本着支持国产数据库的原则,写几篇试用感受。
  由于本人唯一熟悉的数据库就是Oracle,因此所有的对比都是与Oracle数据库进行对比,在这个过程中,将尽可能避免将对Oracle数据库的喜爱之情带进来,争取站在一个比较公正的位置上来进行评价。
  这一篇简单介绍一下达梦数据库的安装过程。

  我拿到的是达梦6.0 for Windows 32位的企业版,安装文件大小115M。这个安装文件的大小也就和EXCEL、ACCESS是一个数量级的,甚至还要更小一些,与安装文件1个G以上的Oracle 11g相比,整整小了一个数量级,更不用说一个是刚刚进入市场的国产数据库,而另一个是市场占有量超过50%的最灵活最复杂的数据库,因此不能指望二者能提供相同甚至相似的功能,主要是看看达梦能够提供到什么地步的功能。
  达梦数据库对系统的硬件要求:奔腾2(建议奔腾3 800以上)、内存256M(建议512M)、硬盘5G以上。这种硬件要求基本上可以不用考虑了,现在很少能找到不满足这个硬件要求的PC机,更不用说服务器了。
  软件要求Windows 2000以上,支持TCP/IP协议。
  安装准备工作比较有趣:要求关闭杀毒、安全防护软件。似乎安装程序与杀毒软件的兼容性还存在一些问题。更有意思的一点是,要求操作系统时间在1970年1月1日0:0:0到2038年1月19日3:14:7之间。看来系统的日期类型字段应该是利用一个长整型数值来保存,存储的是从1970年1月1日0:0:0时以来的秒值:

SQL> SELECT TO_CHAR(
  2     TO_DATE('1970-1-1 0:0:0', 'YYYY-MM-DD HH24:MI:SS')
  3             + (POWER(2, 31) - 1)/24/3600,
  4     'YYYY-MM-DD HH24:MI:SS')
  5  FROM DUAL;
TO_CHAR(TO_DATE('19
-------------------
2038-01-19 03:14:07

  这是32位所能支持的最大值,不过这对于系统而言,似乎略显不足,毕竟显然已经到了2010年,难保系统中会出现超过2038年的日期。如果不考虑正负的问题,32位系统所能支持的上限是:

SQL> SELECT TO_CHAR(
  2     TO_DATE('1970-1-1 0:0:0', 'YYYY-MM-DD HH24:MI:SS')
  3             + (POWER(2, 32) - 1)/24/3600,
  4     'YYYY-MM-DD HH24:MI:SS')
  5  FROM DUAL;
TO_CHAR(TO_DATE('19
-------------------
2106-02-07 06:28:15

  这对于绝大部分情况来说,应该足够了。不过要解决根本问题,恐怕需要64位系统的支持了。
  下面还是回到正题,双机SETUP.EXE开始安装:
  首先出现安装语言选择画面,选择简体中文后,进入到安装向导画面。这个画面没有任何可选项,点击下一步继续。
  接着出现常见的许可证协议,选择接受后继续;
  出现的是达梦安装产品明显列表,当前的服务器版本是6.0.2.51p6;
  接着是验证KEY的步骤,选择License文件的路径,找到对应的key文件,打开后安装界面显示有效期、用户名、服务器颁布类型、发布类型、授权用户数和并发连接数,确认后进入下一步;
  选择安装类型,这里有典型安装、服务器安装、客户端安装和自定义四个选项,看了一下典型安装似乎就是完全安装,下一层大的选项包括服务器端、客户端、集群组件和帮助,完全安装需要482.5M,和Oracle的安装软件大小相比,恰好又是十分之一。全部选择后,点击下一步;
  安装目录选择,这里选择安装初始数据库数据、选择高级配置、并设置数据文件的保存位置最后安装示例库,大约总共需要占用900M的空间;
  由于选择了高级配置,显然进入数据库配置页面:
  首先选择数据页大小,有4、8、16、32K四个选项,推荐是8K,莫非达梦数据库的这个数据页的概念和SQLSERVER、SYBASE的数据页有点相似;
  随后是数据文件簇大小,有16K和32K两个选项,推荐是16K,这个参数个人感觉类似Oracle中的BLOCKSIZE;
  是否设置大小写敏感,推荐为否;
  使用UNICODE字符集,推荐为否;
  空串’’按NULL来处理,推荐为否;
  除了最后一个空字符串的设置外,其他选择推荐值,而最后一个根据Oracle中的情况,选择了空字符串作为NULL来处理;
  下面是修改口令页面,可以修改SYSDBA、SYSAUDITOR和SYSSS0的口令,其中SYSSSO需要安全版才能修改;
  选择“开始菜单”文件夹页面,这里“达梦数据库”将被添加到开始菜单中;
  进入小结页面,刚才一些关键性信息的总结会列出来,确认无误后开始安装。
  安装过程用了不到四分钟,在安装前和过程中,我没有关闭杀毒软件和防火期,安装顺利结束。
  安装过程十分的简单,不过Windows下的安装看不出什么,毕竟一个初学者也能在Windows的环境下搞定Oracle的安装。
  关于License想多说几句,达梦数据库打算作为产品面向市场,维护自己的知识产权无可厚非。但是要知道,Oracle的安装是不需要任何License的,虽然Oracle数据库都是安装CPU来卖的,一套几十万、上百万甚至是几百万,但是Oracle对于开发者是免费的。换句话说,任何对Oracle有兴趣的人,都可以免费的得到Oracle用来学习,Oracle不但拥有数据库领域最广泛用户群,还拥有最广泛的学习群体和最广泛的爱好者,这也是Oracle为什么如此成功的因素之一。当然Oracle的成功是不可复制的,但是Oracle在推广Oracle技术,降低学习Oracle门槛的方面绝对有值得借鉴之处。
  欲了解更多,点击:http://www.dameng.com/dmweb/article.do?type=category&articleid=57416

[ 本帖最后由 aeonia 于 2010-6-3 01:09 PM 编辑 ]
支持达梦!支持国产数据库第一品牌!
http://www.dameng.com/

TOP

  这一篇简单介绍一下达梦数据库PL/SQL相关的内容。

  达梦数据库对于PL/SQL的支持也是出人意料的,基本上所有的关键性语法都与Oracle的PL/SQL没有本质的区别。


SQL>BEGIN
2   INSERT INTO T VALUES (3, 'PL/SQL', SYSDATE);
3   END;
4   /
BEGIN
INSERT INTO T VALUES (3, 'PL/SQL', SYSDATE);
END;
1 rows affected
time used: 68.921(ms) clock tick:115154870.
SQL>BEGIN
2   EXECUTE IMMEDIATE 'TRUNCATE TABLE T';
3   END;
4   /
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE T';
END;
0 rows affected
time used: 31.029(ms) clock tick:51357350.
SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
0 rows got
time used: 0.278(ms) clock tick:449080.


  可以看到,不仅支持PL/SQL中包含的DML语句,而且连DDL语句都是支持的。


SQL>DECLARE
2       V_FLAG BOOLEAN;
3   BEGIN
4       FOR I IN 2 .. 100 LOOP
5               V_FLAG := TRUE;
6               FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
7                       IF MOD(I,J) = 0 THEN
8                               V_FLAG := FALSE;
9                               EXIT;
10                      END IF;
11              END LOOP;
12
13              IF V_FLAG = TRUE THEN
14                      --DBMS_OUTPUT.PUT_LINE(I);
15                      NULL;
16              END IF;
17      END LOOP;
18  END;
19  /
DECLARE
        V_FLAG BOOLEAN;
BEGIN
        FOR I IN 2 .. 100 LOOP
                V_FLAG := TRUE;
                FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
                        IF MOD(I,J) = 0 THEN
                                V_FLAG := FALSE;
                                EXIT;
                        END IF;
                END LOOP;
                IF V_FLAG = TRUE THEN
                        --DBMS_OUTPUT.PUT_LINE(I);
                        NULL;
                END IF;
        END LOOP;
END;
0 rows affected
time used: 108.993(ms) clock tick:181319230.


  这时Oracle中计算100以内质数的一个PL/SQL过程,可以看到,除了调用DBMS_OUTPUT包之外,其他部分不用进行任何的修改就可以顺利执行,在达梦的PL/SQL语句中,提供了PRINT语句来代替DBMS_OUTPUT包:


SQL>DECLARE
2       V_FLAG BOOLEAN;
3   BEGIN
4       FOR I IN 2 .. 100 LOOP
5               V_FLAG := TRUE;
6               FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
7                       IF MOD(I,J) = 0 THEN
8                               V_FLAG := FALSE;
9                               EXIT;
10                      END IF;
11              END LOOP;
12
13              IF V_FLAG = TRUE THEN
14                      PRINT(I);
15              END IF;
16      END LOOP;
17  END;
18  /
DECLARE
        V_FLAG BOOLEAN;
BEGIN
        FOR I IN 2 .. 100 LOOP
                V_FLAG := TRUE;
                FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
                        IF MOD(I,J) = 0 THEN
                                V_FLAG := FALSE;
                                EXIT;
                        END IF;
                END LOOP;
                IF V_FLAG = TRUE THEN
                        PRINT(I);
                END IF;
        END LOOP;
END;
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
0 rows affected
time used: 29.325(ms) clock tick:48929860.


  除了匿名块外,达梦还支持PROCEDURE、FUNCTION和TRIGGER:


SQL>CREATE OR REPLACE PROCEDURE P_TEST AS
2   BEGIN
3   INSERT INTO T VALUES (1, 'TEST', SYSDATE);
4   COMMIT;
5   END;
6   /
CREATE OR REPLACE PROCEDURE P_TEST AS
BEGIN
INSERT INTO T VALUES (1, 'TEST', SYSDATE);
COMMIT;
END;
time used: 41.239(ms) clock tick:68574010.
SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
0 rows got
time used: 0.319(ms) clock tick:520320.
SQL>BEGIN
2   P_TEST;
3   END;
4   /
BEGIN
P_TEST;
END;
1 rows affected
time used: 11.769(ms) clock tick:19487570.
SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
1       1       TEST    2010-04-07
1 rows got
time used: 0.295(ms) clock tick:477140.


  看一个函数的例子:


SQL>CREATE OR REPLACE FUNCTION F_TAX
2   (P_SALARY IN NUMBER, P_START IN NUMBER DEFAULT 2000)
3   RETURN NUMBER AS
4       V_SALARY NUMBER := P_SALARY - P_START;
5   BEGIN
6       IF V_SALARY <= 0 THEN
7               RETURN 0;
8       ELSIF V_SALARY <= 500 THEN
9               RETURN V_SALARY * 0.05;
10      ELSIF V_SALARY <= 2000 THEN
11              RETURN V_SALARY * 0.1 - 25;
12      ELSIF V_SALARY <= 5000 THEN
13              RETURN V_SALARY * 0.15 - 125;
14      ELSIF V_SALARY <= 20000 THEN
15              RETURN V_SALARY * 0.2 - 375;
16      ELSIF V_SALARY <= 40000 THEN
17              RETURN V_SALARY * 0.25 - 1375;
18      ELSIF V_SALARY <= 60000 THEN
19              RETURN V_SALARY * 0.3 - 3375;
20      ELSIF V_SALARY <= 80000 THEN
21              RETURN V_SALARY * 0.35 - 6375;
22      ELSIF V_SALARY <= 100000 THEN
23              RETURN V_SALARY * 0.4 - 10375;
24      ELSE
25              RETURN V_SALARY * 0.45 - 15375;
26      END IF;
27  END;
28  /
CREATE OR REPLACE FUNCTION F_TAX
(P_SALARY IN NUMBER, P_START IN NUMBER DEFAULT 2000)
RETURN NUMBER AS
        V_SALARY NUMBER := P_SALARY - P_START;
BEGIN
        IF V_SALARY <= 0 THEN
                RETURN 0;
        ELSIF V_SALARY <= 500 THEN
                RETURN V_SALARY * 0.05;
        ELSIF V_SALARY <= 2000 THEN
                RETURN V_SALARY * 0.1 - 25;
        ELSIF V_SALARY <= 5000 THEN
                RETURN V_SALARY * 0.15 - 125;
        ELSIF V_SALARY <= 20000 THEN
                RETURN V_SALARY * 0.2 - 375;
        ELSIF V_SALARY <= 40000 THEN
                RETURN V_SALARY * 0.25 - 1375;
        ELSIF V_SALARY <= 60000 THEN
                RETURN V_SALARY * 0.3 - 3375;
        ELSIF V_SALARY <= 80000 THEN
                RETURN V_SALARY * 0.35 - 6375;
        ELSIF V_SALARY <= 100000 THEN
                RETURN V_SALARY * 0.4 - 10375;
        ELSE
                RETURN V_SALARY * 0.45 - 15375;
        END IF;
END;
time used: 4.685(ms) clock tick:5683670.
SQL>SELECT F_TAX(10000) FROM T;
SELECT F_TAX(10000) FROM T;

1       1225
1 rows got
time used: 30.050(ms) clock tick:50174960.


  这时以前写的一个计算个人所得税的函数,同样没有做任何的修改,放在达梦数据库上就可以直接运行。下面是一个PACKAGE的例子:


SQL>CREATE OR REPLACE PACKAGE PA_TEST AS
2       PROCEDURE P_TEST(P_IN NUMBER);
3       PROCEDURE P_TEST(P_IN VARCHAR);
4   END;
5   /
CREATE OR REPLACE PACKAGE PA_TEST AS
        PROCEDURE P_TEST(P_IN NUMBER);
        PROCEDURE P_TEST(P_IN VARCHAR);
END;
time used: 80.545(ms) clock tick:134160000.
SQL>CREATE OR REPLACE PACKAGE BODY PA_TEST AS
2       PROCEDURE P_TEST(P_IN NUMBER) AS
3       BEGIN
4               PRINT('NUMBER');
5       END;
6
7       PROCEDURE P_TEST(P_IN VARCHAR) AS
8       BEGIN
9               PRINT('VARCHAR');
10      END;
11  END;
12  /
CREATE OR REPLACE PACKAGE BODY PA_TEST AS
        PROCEDURE P_TEST(P_IN NUMBER) AS
        BEGIN
                PRINT('NUMBER');
        END;
        PROCEDURE P_TEST(P_IN VARCHAR) AS
        BEGIN
                PRINT('VARCHAR');
        END;
END;
time used: 20.445(ms) clock tick:33862040.
SQL>BEGIN
2   PA_TEST.P_TEST(1);
3   END;
4   /
BEGIN
PA_TEST.P_TEST(1);
END;
NUMBER
0 rows affected
time used: 0.552(ms) clock tick:913600.
SQL>BEGIN
2   PA_TEST.P_TEST('1');
3   END;
4   /
BEGIN
PA_TEST.P_TEST('1');
END;
VARCHAR
0 rows affected
time used: 0.441(ms) clock tick:725060.


  这个例子显示了包中过程的重载特性。看一个触发器的例子:


SQL>CREATE OR REPLACE TRIGGER T_TRI
2   BEFORE DELETE ON T
3   FOR EACH ROW
4   BEGIN
5   INSERT INTO T_BAK VALUES (:OLD.ID);
6   END;
7   /
CREATE OR REPLACE TRIGGER T_TRI
BEFORE DELETE ON T
FOR EACH ROW
BEGIN
INSERT INTO T_BAK VALUES (:OLD.ID);
END;
time used: 13.493(ms) clock tick:22369710.
SQL>INSERT INTO T VALUES (2, 'ABC', SYSDATE);
INSERT INTO T VALUES (2, 'ABC', SYSDATE)
1 rows affected
time used: 0.376(ms) clock tick:614380.
SQL>INSERT INTO T VALUES (3, 'TTT', NULL);
INSERT INTO T VALUES (3, 'TTT', NULL)
1 rows affected
time used: 0.497(ms) clock tick:818040.
SQL>DELETE T;
DELETE T;
3 rows affected
time used: 0.730(ms) clock tick:1203390.
SQL>SELECT * FROM T_BAK;
SELECT * FROM T_BAK;
ID
1       1
2       2
3       3
3 rows got
time used: 0.370(ms) clock tick:602660.


  达梦支持这种最普通的DML的触发器,还支持INSTEAD OF触发器、但是并不支持基于数据库事件的触发器和基于数据库错误的触发器。达梦数据库的FETCH语句和PL/SQL的相比更加灵活一些,提供了随机读取的功能:


SQL>INSERT INTO T VALUES (1, 'A', NULL);
INSERT INTO T VALUES (1, 'A', NULL)
1 rows affected
time used: 0.461(ms) clock tick:757930.
SQL>INSERT INTO T VALUES (2, 'B', SYSDATE);
INSERT INTO T VALUES (2, 'B', SYSDATE)
1 rows affected
time used: 0.430(ms) clock tick:701910.
SQL>INSERT INTO T VALUES (3, 'ABC', '');
INSERT INTO T VALUES (3, 'ABC', '')
1 rows affected
time used: 0.333(ms) clock tick:540330.
SQL>DECLARE
2       V_NUM NUMBER;
3       C_CUR CURSOR;
4   BEGIN
5       OPEN C_CUR FOR 'SELECT ID FROM T';
6       FETCH LAST C_CUR INTO V_NUM;
7       PRINT(V_NUM);
8       FETCH PRIOR C_CUR INTO V_NUM;
9       PRINT(V_NUM);
10      FETCH ABSOLUTE 0 C_CUR INTO V_NUM;
11      PRINT(V_NUM);
12      CLOSE C_CUR;
13  END;
14  /
DECLARE
        V_NUM NUMBER;
        C_CUR CURSOR;
BEGIN
        OPEN C_CUR FOR 'SELECT ID FROM T';
        FETCH LAST C_CUR INTO V_NUM;
        PRINT(V_NUM);
        FETCH PRIOR C_CUR INTO V_NUM;
        PRINT(V_NUM);
        FETCH ABSOLUTE 0 C_CUR INTO V_NUM;
        PRINT(V_NUM);
        CLOSE C_CUR;
END;
3
2
1
0 rows affected
time used: 0.726(ms) clock tick:1199160.


  其中FETCH语句指定ABSOLUTE的数值时,是从0开始的,这显然是C语言的习惯。达梦数据库还有一个优点,无论是匿名块还是过程,在SELECT的时候可以不指定FETCH的变量,这时会将查询结果直接输出到屏幕上:


SQL>BEGIN
2   SELECT * FROM T;
3   END;
4   /
BEGIN
SELECT * FROM T;
END;
id              name            create_date
1       1       A       NULL
2       2       B       2010-04-07
3       3       ABC     NULL
3 rows got
time used: 0.496(ms) clock tick:816250.


  不过达梦数据库的PL/SQL也有不足之处,比如不支持TYPE,不支持索引表、嵌套表和数组。由于不支持嵌套表和索引表,显然也是不支持批量操作的,无论是批量插入和批量读取都是达梦目前所不支持的。
       欲了解更多,点击:http://www.dameng.com/dmweb/article.do?type=category&articleid=57416

[ 本帖最后由 aeonia 于 2010-5-26 10:29 AM 编辑 ]
支持达梦!支持国产数据库第一品牌!
http://www.dameng.com/

TOP

  这一篇简单介绍一下达梦数据库SQL相关的内容。


  利用上一篇文章搭建的测试环境,首先登陆数据库:


C:\dmdbms\bin>isql
isql V6.0.2.51-Build(2009.12.23)
SQL>login
server name:localhost
user name:test
password:
port:12345
dm_login time used:176.475(ms)
SQL>


  首先测试DML语句,达梦数据库支持SQL92标准,且兼容Oracle8i的语法,下面测试一下:


SQL>INSERT INTO T
2   VALUES (1, 'TEST', SYSDATE);
INSERT INTO T
VALUES (1, 'TEST', SYSDATE)
1 rows affected
time used: 0.343(ms) clock tick:551330.
SQL>INSERT INTO T
2   VALUES (2, 'TEST AGAIN', TO_DATE('2010-3-31', 'YYYY-MM-DD'));
INSERT INTO T
VALUES (2, 'TEST AGAIN', TO_DATE('2010-3-31', 'YYYY-MM-DD'))
1 rows affected
time used: 0.516(ms) clock tick:848580.
SQL>UPDATE T
2   SET NAME = 'NEWNAME'
3   WHERE ID = 2;
UPDATE T
SET NAME = 'NEWNAME'
WHERE ID = 2;
1 rows affected
time used: 0.498(ms) clock tick:818000.
SQL>INSERT INTO T
2   SELECT ROWNUM + ID, NAME, CREATE_DATE
3   FROM T;
INSERT INTO T
SELECT ROWNUM + ID, NAME, CREATE_DATE
FROM T;
2 rows affected
time used: 67.481(ms) clock tick:112655890.
SQL>COMMIT;
COMMIT;
time used: 11.671(ms) clock tick:19334860.
SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
1       1       TEST    2010-03-31
2       2       NEWNAME 2010-03-31
3       2       TEST    2010-03-31
4       4       NEWNAME 2010-03-31
4 rows got
time used: 0.385(ms) clock tick:631120.
SQL>DELETE T WHERE ID = 3;
DELETE T WHERE ID = 3;
0 rows affected
time used: 0.442(ms) clock tick:721900.
SQL>DELETE T WHERE ID = 4;
DELETE T WHERE ID = 4;
1 rows affected
time used: 0.475(ms) clock tick:780110.
SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
1       1       TEST    2010-03-31
2       2       NEWNAME 2010-03-31
3       2       TEST    2010-03-31
3 rows got
time used: 0.321(ms) clock tick:520970.


  最基本的SELECT、INSERT、UPDATE、DELETE操作没有问题,甚至连ORACLE语法中的ROWNUM都支持。在ISQL显示结果中,有一个自动的行号显示,但是列名显示的时候没有将这一位空出来,使得ID列跑到了行号的位置上,比较容易引起误解。


SQL>MERGE INTO T
2   USING (SELECT ID + 1 ID, NAME, CREATE_DATE FROM T) T1
3   ON (T.ID = T1.ID)
4   WHEN MATCHED THEN UPDATE
5   SET T.NAME = T1.NAME, T.CREATE_DATE = T1.CREATE_DATE
6   WHEN NOT MATCHED THEN INSERT
7   VALUES (T1.ID, T1.NAME, T1.CREATE_DATE);


  第1行: 'INTO'附近有语法错误


SQL>SELECT * FROM T
2   START WITH ID = 1
3   CONNECT BY PRIOR ID = ID + 1;
SELECT * FROM T
START WITH ID = 1
CONNECT BY PRIOR ID = ID + 1;
id              name            create_date
1       1       TEST    2010-03-31
1 rows got
time used: 54.497(ms) clock tick:90706490.


  Oracle9i新增的MERGE语句果然是不支持的,而Oracle特有的树形查询居然是可以的,甚至连LEVEL伪列都是支持的:


SQL>SELECT T.*, LEVEL
2   FROM T
3   START WITH ID = 1
4   CONNECT BY ID = PRIOR ID + 1;
SELECT T.*, LEVEL
FROM T
START WITH ID = 1
CONNECT BY ID = PRIOR ID + 1;
id              name            create_date             LEVEL
1       1       TEST    2010-03-31      1
2       2       NEWNAME 2010-03-31      2
3       2       TEST    2010-03-31      2
3 rows got
time used: 35.683(ms) clock tick:59512460.


  下面看看对其他Oracle特有的语法支持的如何:


SQL>SELECT *
2   FROM T, T1
3   WHERE T.ID = T1.ID;
SELECT *
FROM T, T1
WHERE T.ID = T1.ID;
id              name            create_date             ID
1       1       TEST    2010-03-31      1
1 rows got
time used: 0.521(ms) clock tick:855860.
SQL>SELECT *
2   FROM T, T1
3   WHERE T.ID = T1.ID (+);
SELECT *
FROM T, T1
WHERE T.ID = T1.ID (+);
id              name            create_date             ID
1       1       TEST    2010-03-31      1
2       2       NEWNAME 2010-03-31      NULL
3       2       TEST    2010-03-31      NULL
3 rows got
time used: 36.644(ms) clock tick:61195700.


  不但普通的连接支持,连Oracle的外连接’+’都是支持的。


SQL>SELECT *
2   FROM
3   (
4       SELECT ROWNUM RN, A.*
5       FROM
6       (
7               SELECT T.*
8               FROM T, T1
9               WHERE T.ID = T1.ID(+)
10              ORDER BY 2, 1
11      ) A
12      WHERE ROWNUM <= 5
13  )
14  WHERE RN > 1;
SELECT *
FROM
(
        SELECT ROWNUM RN, A.*
        FROM
        (
                SELECT T.*
                FROM T, T1
                WHERE T.ID = T1.ID(+)
                ORDER BY 2, 1
        ) A
        WHERE ROWNUM <= 5
)
WHERE RN > 1;
RN              id              name            create_date
1       2       1       TEST    2010-03-31
2       3       2       TEST    2010-03-31
2 rows got
time used: 30.910(ms) clock tick:51615050.


  Oracle的标准分页语句是支持的,查询子查询语句是支持的,ORDER BY常量代替列名也是支持的。


SQL>SELECT ROW_NUMBER() OVER(ORDER BY NAME, ID DESC) RN,
2   ID,
3   NAME
4   FROM T;


  第1行: '('附近有语法错误。显然分析函数是不支持的,虽然分析函数在8i就出现了,不过确实属于Oracle比较特有的技术,达梦不支持分析函数并不意外。


SQL>SELECT NAME, MAX(ID)
2   FROM T
3   GROUP BY NAME
4   HAVING COUNT(*) > 1;
SELECT NAME, MAX(ID)
FROM T
GROUP BY NAME
HAVING COUNT(*) > 1;
NAME
1       TEST    2
1 rows got
time used: 0.583(ms) clock tick:963240.
SQL>SELECT NAME, AVG(ID)
2   FROM T
3   GROUP BY ROLLUP(NAME);
SELECT NAME, AVG(ID)
FROM T
GROUP BY ROLLUP(NAME);


  无效的存储过程名 'ROLLUP' .error code = -1024。显然聚集函数、GROUP BY语句和HAVING语句都是支持的。但是8i开始Oracle对GROUP BY提供了ROLLUP和CUBE功能,而这显然是达梦所不支持的,既然ROLLUP和CUBE不支持,那么对应的GROUPING等CUBE和ROLLUP专用的函数肯定也是不支持的。


SQL>SELECT T.ID, T1.ID ID1
2   FROM T, T1
3   WHERE T.ID = T1.ID (+)
4   ORDER BY 2 NULLS FIRST;


  第4行: 'NULLS'附近有语法错误。支持ORDER BY语句,但是Oracle的NULLS LAST和NULLS FIRST语法并不支持。


SQL>SELECT ID, (SELECT ID FROM T1 WHERE T1.ID = T.ID)
2   FROM T;
SELECT ID, (SELECT ID FROM T1 WHERE T1.ID = T.ID)
FROM T;
ID
1       1       1
2       2       NULL
3       2       NULL
3 rows got
time used: 0.556(ms) clock tick:916730.


  将子查询作为查询列的方式居然也是支持的,这是没有想到的。


SQL>SELECT DECODE(ID, 1, 'A', 2, 'B', 'C')
2   FROM T;
SELECT DECODE(ID, 1, 'A', 2, 'B', 'C')
FROM T;

1       A
2       B
3       B
4       C
4 rows got
time used: 32.734(ms) clock tick:54721350.
SQL>SELECT CASE ID WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
2   FROM T;
SELECT CASE ID WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
FROM T;

1       A
2       B
3       B
4       C
4 rows got
time used: 0.439(ms) clock tick:724740.


  达梦还支持DECODE函数和CASE语法。


SQL>SELECT * FROM T;
SELECT * FROM T;
id              name            create_date
1       1       TEST    2010-03-31
2       2       NEWNAME 2010-03-31
3       2       TEST    2010-03-31
3 rows got
time used: 0.385(ms) clock tick:630330.
SQL>DELETE T WHERE ID = 2 AND ROWNUM = 1;
DELETE T WHERE ID = 2 AND ROWNUM = 1;
1 rows affected
time used: 0.611(ms) clock tick:1004030.
SQL>ALTER TABLE T ADD PRIMARY KEY (ID);
ALTER TABLE T ADD PRIMARY KEY (ID);
time used: 14.329(ms) clock tick:23647990.
SQL>ALTER TABLE T1 ADD PRIMARY KEY (ID);
ALTER TABLE T1 ADD PRIMARY KEY (ID);
time used: 12.599(ms) clock tick:20886900.
SQL>UPDATE
2   (SELECT T.ID, T.NAME
3   FROM T, T1
4   WHERE T.ID = T1.ID)
5   SET NAME = 'A';


  第2行: '('附近有语法错误。


SQL>UPDATE T A
2   SET (NAME, CREATE_DATE) =
3       (SELECT NAME, CREATE_DATE FROM T WHERE ID = A.ID);


  第3行: 'SELECT'附近有语法错误。最后测试了一下UPDATE子查询方式,显然这也是达梦数据库所不支持的,不过这种语法在Oracle8i中已经出现了。另一种通过子查询同时更新多个列的写法也是不支持的。


SQL>login
server name:localhost
user name:sysdba
password:
port:12345
dm_login time used:43.856(ms)
SQL>select * from dual;
select * from dual;
SYSDUAL_COL
1       1
1 rows got
time used: 40.933(ms) clock tick:68373830.


  达梦为了兼容Oracle还特意构造了一个DUAL表。虽然字段名称以及记录的值和Oracle并不相同,但是无论是字段名还是记录的值都是不重要的,重要的是表中只有一个字段且只有一条记录。
简单总结一下,达梦数据库在文档中说已经支持Oracle8i的语法,当时看到这种说明心里不以为然,要知道Oracle有很多语法是SQL92标准所不支持的,比如查询子查询、外连接、树形查询等等。但是测试的结果确实出乎意料,进行了众多的测试,既然只有寥寥几种写法是达梦不支持的,其中还要去掉MERGE语句,因为这是9i才引入的新特性。


  除了支持SQL92语法,以及一些常见的语法外,达梦还支持下列Oracle特有的语法:包括树形查询、外连接、ROWNUM伪列、LEVEL伪列、DUAL表、标准分页查询、甚至包括子查询作为查询列。其中达梦对于树形查询的支持比较出乎意料,不仅支持LEVEL伪列,还支持CONNECT_IS_LEAF和CONNECT_IS_CYCLE伪列,还支持CONNECT BY NOCYCLE语句,以及CONNECT_BY_ROOT操作、SYS_CONNECT_BY_PATH函数。虽然达梦中所有树形查询的语法并没有超过Oracle中的语法,但是这些伪列、函数和操作已经远远超过8i中Oracle的语法了,已经完全可以支持Oracle10g中树形查询的语法和功能了。


  而在不支持的特性包括分析函数、ROLLUP和CUBE相关的GROUP BY语句、ORDER BY语句中的NULLS FIRST或NULLS LAST语句、UPDATE或DELETE子查询语句。其中分析函数不支持再正常不过,这是Oracle提供的一个独特的强大工具,能在记录行级进行排序、分区等复杂的操作。而GROUP BY的ROLLUP和CUBE的实现应该不算太复杂,不过毕竟这部分更多的是用在数据仓库中,在OLTP环境下很少可以用到,不支持也不会有多大的影响。而ORDER BY中的NULLS FIRST和NULLS LAST语句不支持就不太应该了,这应该是经常会使用的功能,而且实现起来应该也很容易,怀疑是被遗漏的功能。至于UPDATE或DELETE子查询,这也是Oracle非常独特的写法,其中还涉及键值保留表的概念,因此不支持也是在情理之中。但是对于根据查询结果同时更新多个列的情况还是比较常见的,这种写法不但简单,而且可以避免子查询执行多次,这种UPDATE方式还是应该支持的。


  从目前看,将8i的SQL的语句迁移到达梦数据库上而不做修改还是可行的,九成以上的功能都已经实现了。不过在Oracle的9/10/11版本中,又增加了大量的新的语法,比如MERGE、INSERT ALL、WITH、AS OF、MODEL等等,如果达梦的新版本想要兼容Oracle新版本中的语法,还是有不少难度的。

  最后看看达梦中特有的写法,说是特有只是针对Oracle而言,这种语法早在SQLSERVER中就存在了:


SQL>SELECT TOP 2 *
2   FROM T
3   ORDER BY ID;
SELECT TOP 2 *
FROM T
ORDER BY ID;
id              name            create_date
1       1       TEST    2010-03-31
2       2       TEST    2010-03-31
2 rows got
time used: 31.185(ms) clock tick:52131540.
SQL>SELECT * FROM T
2   LIMIT 2 OFFSET 1;
SELECT * FROM T
LIMIT 2 OFFSET 1;
id              name            create_date
1       2       NEWNAME 2010-03-31
2       2       TEST    2010-03-31
2 rows got
time used: 0.469(ms) clock tick:772680.


  前一个是获取前N条记录的方法,相当于Oracle标准分页方式,不过语法要比标准分页简单得多。后面一个语句是在结果集中获取指定位置开始的N条记录。在Oracle中可以通过ROWNUM或分析函数实现同样的功能,不过语句要复杂一些。
支持达梦!支持国产数据库第一品牌!
http://www.dameng.com/

TOP

支持达梦!支持国产数据库第一品牌!
http://www.dameng.com/

TOP

比较深入!好!
http://oklab.5d6d.com

TOP

发新话题