【赵渝强老师】达梦数据库的数据库对象

简介: 达梦数据库包含基本与复杂两大类数据库对象。基本对象如表、索引、视图、序列和同义词,通过单一DDL语句创建和管理。表是数据存储核心,支持多种数据类型;索引提升查询速度,常见类型包括聚集、唯一、函数等索引;视图提供虚表功能;序列生成有序整数;同义词简化对象访问。复杂对象包括存储过程、函数和触发器,需用DMSQL语言开发,适用于更复杂的业务逻辑处理。文中通过实例详细介绍了各类对象的创建与使用方法。

b300.png

达梦数据库中包含各种数据库对象,主要分为两大类型:基本数据库对象和复杂数据库对象。下面分别进行介绍。视频讲解如下:


一、 基本数据库对象

常见的基本数据库对象有:表、索引、视图、序列、同义词等。之所以叫做基本数据库对象是因为这些对象直接使用一条DDL(Data Definition Language,数据定义语言)语句即可创建和管理。


1.1  表


表是一种非常重要的数据库对象,DM数据库的数据都是存储在表中。DM数据库的表是一种二维结构,由行和列组成。表有列组成,列有列的数据类型。达梦数据库支持的数据类型主要有常规数据类型、位串数据类型、日期时间数据类型和多媒体数据类型。


这里值得说明的是,char(n)和varchar(n)中括号中n代表字符的个数,并不代表字节个数,比如char(30) 就可以存储30个字符。char和varchar 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。


下面通过一个例子来说明char和varchar在存储字符的时候的区别。

(1)创建表一张新的表

SQL> create table test1(v1 char(5),v2 varchar(5));


(2)往表中插入数据

SQL> insert into test1 values('abc  ','abc  ');


(3)查询表中的数据

SQL> select concat(v1,'*'),concat(v2,'*') from test1;
# 输出的结果如下:
行号     CONCAT(V1,'*') CONCAT(V2,'*')
---------- -------------- --------------
1          abc  *         abc*
# 从输出的结果可以看出,char同varchar 的区别在于前者长度不足时,
# 系统自动填充空格,而后者只占用实际的字节空间。另外,
# 实际插入表中的列长度要受到记录长度的约束,
# 每条记录总长度不能大于页面大小的一半。


1.2  索引

索引是与表相关的可选的结构(聚簇索引除外),它能使对应于表的SQL语句执行得更快,因为有索引比没有索引能更快地定位信息。DM8数据库的索引能提供访问表的数据的更快路径,可以不用重写任何查询而使用索引,其结果与不使用索引是一样的,但速度更快。DM数据库官方对索引的定义为:索引(Index)是帮助DM数据库高效获取数据的数据结构。DM数据库中默认索引类型是B+树索引。


达梦数据库提供了几种最常见类型的索引,对不同场景有不同的功能,它们是:

  • 聚集索引:每一个普通表有且只有一个聚集索引;
  • 唯一索引:索引数据根据索引键唯一;
  • 函数索引:包含函数/表达式的预先计算的值;
  • 位图索引:对低基数的列创建位图索引;
  • 位图连接索引:针对两个或者多个表连接的位图索引,主要用于数据仓库中;
  • 全文索引:在表的文本列上而建的索引。


# 提示:索引在逻辑上和物理上都与相关的表的数据无关,作为无关的结构,索引需要存储空间。 
# 创建或删除一个索引,不会影响基本的表、数据库应用或其他索引。
# 当插入、更改和删除相关的表的行时,达梦数据库会自动管理索引。
# 如果删除索引,所有的应用仍继续工作,但访问以前被索引了的数据时速度可能会变慢。


可以用create index语句明确地创建索引。下面通过一个简单的示例来演示如何创建普通的索引。

(1)在emp表的ename列上创建一个名为index_emp_ename的索引。

SQL> create index index_emp_ename on emp(ename);


(2)获取索引的ID号。

SQL> select name,id from sysobjects 
      where name='INDEX_EMP_ENAME' and subtype$='INDEX';
# 输出的信息如下:
行号        NAME              ID         
---------- --------------- -----------
1           INDEX_EMP_ENAME 33555654


(3)通过indexdef系统函数查看索引的定义。

SQL> select indexdef(33555654, 0);
# 输出的信息如下:
行号        INDEXDEF(33555654,0)                                                                  
---------- ----------------------------------------------
1             CREATE INDEX "INDEX_EMP_ENAME" 
                ON "EMP"("ENAME" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
# 函数indexdef的定义如下:indexdef(index_id int, preflag int);
# 其中:
# index_id:索引id
# preflag:对象前缀个数。1表示导出模式名;0表示只导出对象名


(4)查询名叫KING的员工数据,并输出对应的SQL执行计划。

SQL> explain select * from emp where ename='KING';
# 输出的信息如下:
1   #NSET2: [1, 1, 172] 
2     #PRJT2: [1, 1, 172]; exp_num(9), is_atom(FALSE) 
3       #BLKUP2: [1, 1, 172]; INDEX_EMP_ENAME(EMP)
4         #SSEK2: [1, 1, 172]; scan_type(ASC), 
                                   INDEX_EMP_ENAME(EMP), 
                                   scan_range['KING','KING']
# 从输出的执行计划可以看出,该查询使用了索引index_emp_ename。


(5)使用系统函数sp_rebuild_index重建索引。

SQL> sp_rebuild_index('SCOTT', 33555660);
# 提示:当一个表经过大量的增删改操作后,表的数据在物理文件中可能存在大量碎片,从而影响访问速度。
# 另外,当删除表的大量数据后,若不再对表执行插入操作,索引所处的段可能占用了大量并不使用的簇,
# 从而浪费了存储空间。可以使用重建索引来对索引的数据进行重组,使数据更加紧凑,
# 并释放不需要的空间,从而提高访问效率和空间效率。
# DM8提供的重建索引的系统函数为:
# sp_rebuild_index(schema_name varchar(256), index_id int);
# 其中:
# scheam_name为索引所在的模式名
# index_id为索引id。
# 使用说明:
# 水平分区子表,临时表和系统表上建的索引不支持重建。
# 虚索引和聚集索引不支持重建。


1.3  视图


视图(VIEW)是一种虚表,其本身并不包含数据。它将作为一个select语句保存在数据字典中的。视图依赖的表叫做基表。通过视图可以展现基表的部分数据;视图数据来自定义视图的查询中使用的基表。在了解的视图的作用后,下面通过具体的步骤来演示如何使用视图。


(1)基于员工表emp创建视图。

SQL> create or replace view view1
as
select * from dmhr.employee where department_id=1001;
# 视图也可以基于多表进行创建,例如:
SQL> create or replace view view2
as
select employee.employee_name,employee.salary,department.department_name 
from dmhr.employee,dmhr.department
where employee.department_id=department.department_id;


(2)从视图中查询数据。

SQL> select employee_name,salary from view1;
# 输出的信息如下:
行号     EMPLOYEE_NAME SALARY     
---------- ------------- -----------
1          龚顺超     8000
2          陈伟婷     15853
3          何杭菊     15868
4          欧锋利     15878
5          薛辉明     15888
SQL> select * from view2 where rownum<=10;
行号     EMPLOYEE_NAME    SALARY      DEPARTMENT_NAME
------ ------------------ ----------- ---------------
1          马学铭        12345       总经理办
2          程擎武        9000        行政部
3          郑吉群        15000       开发部
4          陈仙       12000       市场部
5          金纬       10000       技术支持部
6          李慧军        10000       总经理办
7          常鹏程        5000        行政部
8          谢俊人        5000        市场部
9          苏国华        30000       总经理办
10         强洁芳        10000       行政部
10 rows got
# 这里使用了行号rownum只显示前10条记录。


(3)通过视图执行DML操作,例如:给1001号部门员工涨100块钱工资。

SQL> update view1 set salary=salary+100;
# 并不是所有的视图都可以执行DML操作。在视图定义时含义以下内容,视图则不能执行DML操作:
# (1)查询子句中包含distinct和组函数
# (2)查询语句中包含group by子句和order by子句
# (3)查询语句中包含union 、union all等集合运算符
# (4)where子句中包含相关子查询
# (5)from子句中包含多个表
# (6)如果视图中有计算列,则不能执行update操作
# (7)如果基表中有某个具有非空约束的列未出现在视图定义中,则不能做insert操作


(4)创建视图时使用WITH CHECK OPTION约束。

SQL> create or replace view view3
      as
      select * from dmhr.employee where salary <5000
      with check option;
# 提示:WITH CHECK OPTION表示对视图所做的DML操作,不能违反视图的WHERE条件的限制。


(5)在view3上执行update操作。

SQL> update view3 set salary=10000;
# 此时将出现下面的错误信息:
update view3 set salary=10000;
[-6603]:违反视图[VIEW3]CHECK约束.
已用时间: 4.332(毫秒). 执行号:0.


1.4  序列


序列(sequence)是DM数据库中的数据库实体之一。通过使用序列,多个用户可以产生和使用一组不重复的有序整数值。比如可以用序列来自动地生成主关键字值。序列通过提供唯一数值的顺序表来简化程序设计工作。例如,下面的语句将创建一个序列。


SQL> create sequence myseq;


一旦序列生成,用户就可以在SQL语句中用以下伪列来存取序列的值:

  • currval:返回当前的序列值;
  • nextval:如果为升序序列,序列值增加并返回增加后的值;如果为降序序列,序列值减少并返回减少后的值。


例如:

SQL> select myseq.nextval;
# 输出的信息如下:
行号     NEXTVAL             
---------- --------------------
1          1
SQL> select myseq.currval;  
# 输出的信息如下:
行号     CURRVAL             
---------- --------------------
1          1
# 提示:序列可以是循环的,当序列的值达到最大值/最小值时,序列将从最小值/最大值计数。
# 使用一个序列时,不保证将生成一串连续不断递增的值。例如,如果查询一个序列的下一个值
# 供insert使用,则该查询是能使用这个序列值的唯一会话。如果未能提交事务处理,
# 则序列值就不被插入表中,以后的insert将继续使用该序列随后的值。


1.5  同义词


同义词(Synonym)让用户能够为数据库的一个模式下的对象提供别名。同义词通过掩盖一个对象真实的名字和拥有者,并且对远程分布式的数据库对象给予了位置透明特性以此来提供了一定的安全性。同时使用同义词可以简化复杂的SQL语句。同义词可以替换模式下的表、视图、序列、函数、存储过程等对象。创建同义词的语法格式如下:

create [or replace] [public] synonym 
[<模式名>.]<同义词名> for [<模式名>.]<对象名>


例如,创建一个同义词代表员工表。

SQL> create synonym emp for dmhr.employee;


接下来就可以通过同义词查询员工数据了。

SQL> select count(*) from emp;
# 输出的信息如下:
行号        COUNT(*)            
---------- --------------------
1           858


关于同义词的使用需要注意以下两点:

  • 同义词分为全局同义词(public synonym)和非全局同义词。用户在自己的模式下创建同义词,必须有create synonym权限。用户要创建全局同义词(public synonym),必须有create public synonym权限;
  • 同义词创建时,并不会检查他所指代的同义词对象是否存在,用户使用该同义词时候,如果不存在指代对象或者对该指代对象不拥有权限,则会报错。


二、复杂数据库对象


达梦数据库提供的复杂数据库对象主要包括:存储过程、存储函数和触发器。之所以叫做复杂数据库对象,是因为这些对象需要使用DMSQL语言进行开发和管理。DMSQL程序是达梦数据库对标准SQL语言的扩展,是一种过程化SQL语言。在DMSQL程序中,包括一整套数据类型、条件结构、循环结构和异常处理结构等,DMSQL程序中可以执行SQL语句,SQL语句中也可以使用DMSQL函数。


2.1  存储过程和存储函数


存储过程(Stored Procedure)和存储函数(Stored Function)指存储在数据库中供所有用户调用的子程序,它们事先经过经编译后存储在数据库系统中。因此,调用存储过程和存储函数来完成业务逻辑,是可以提高性能的。存储过程和存储函数的结构类似,但是存储函数必须要有一个return子句用于返回函数的值;而存储过程没有return子句。尽管存储过程没有return子句,但却可以通过指定一个或者多个out参数来指定返回值。

创建存储过程的语法格式如下:

create [or replace] procedure 存储过程名称(参数列表)
as
  DMSQL子程序体;


创建存储函数的基本语法格式如下:

create [or replace] function 存储函数名称(参数列表)
return 函数返回值类型
as
  DMSQL子程序体;


2.1.1  【实战】创建和使用存储过程


下面通过具体的步骤来演示如何创建存储过程,以及如何在DM数据库中调用它。

(1)创建第一个存储过程sayhelloworld,输出Hello World字符串。

SQL> create or replace procedure dmhr.sayhelloworld
as
    --说明部分
begin
    dbms_output.put_line('Hello World');
end;
/


(2)存储过程创建成功后,可以在PL/SQL程序中调用它。例如下面的代码调用了两次存储过程dmhr.sayhelloworld()。

SQL> begin
     dmhr.sayhelloworld();
     dmhr.sayhelloworld();
end;
/
# 输出的信息如下:
Hello World
Hello World
DMSQL 过程已成功完成
已用时间: 0.909(毫秒). 执行号:3528.


(3)存储过程也可以是exec命令单独进行调用,例如:

SQL> exec dmhr.sayhelloworld;
# 输出的信息如下:
Hello World
DMSQL 过程已成功完成
已用时间: 0.455(毫秒). 执行号:3530.


2.1.2  【实战】创建和使用存储函数

存储函数与存储过程的最大区别就在于存储函数可以通过reture子句返回函数的值,而存储过程没有return子句。下面将通过一个具体的示例来演示如何使用存储函数,并且如何调用它。


(1)创建存储函数dmhr.queryEmpTotalIncome查询指定员工的年收入。

SQL> create or replace function dmhr.queryEmpTotalIncome(eno in number)
return number
as
   --定义引用型变量保存月薪和奖金
   psal dmhr.employee.salary%type;
   pcomm dmhr.employee.commission_pct%type;
begin
   -- 查询指定员工的薪水和奖金,并赋值给变量。
   select salary,commission_pct into psal,pcomm from dmhr.employee 
   where employee_id=eno;
  
   --返回年收入
   return psal*12+nvl(pcomm,0);
end;
/


(2)调用存储函数dmhr.queryEmpTotalIncome查询员工号是1001的年收入。

SQL> select dmhr.queryEmpTotalIncome(1001) "该员工的年收入";          
# 输出的信息如下:
行号        该员工的年收入
---------- ---------------------
1           361200


2.2  触发器

触发器是一种特殊的存储过程,它在创建后就存储在数据库中。触发器的特殊性在于它是建立在某个具体的表或视图之上的,或者是建立在各种事件前后的,而且是自动激发执行的,如果用户在这个表上执行了某个DML操作(insert、delete、update),触发器就被激发执行。

触发器常用于自动完成一些数据库的维护工作。例如,触发器可以具有以下功能:

  • 可以对表自动进行复杂的安全性、完整性检查;
  • 可以在对表进行DML操作之前或者之后进行其它处理;
  • 进行审计,可以对表上的操作进行跟踪;
  • 实现不同节点间数据库的同步更新。


DM数据库触发器分为两种不同的类型语句级触发器和元组级触发器,这两种不同类型的触发器在定义是通过for each row进行区分。

  • 语句级触发器

语句级触发器是指在指定的操作语句之前或者之后执行一次,不管这个操作影响了多少行记录。换句话说,语句级触发器针对是表。


  • 元组级触发器

元组级触发器是指触发语句作用的每一条记录都被触发。换句话说,行级级触发器就是针对是表中的每一行。在行级触发器中可以使用:old和:new关键字来表示同一行数据在操作之前和操作之后的值。以员工表(dmhr.employee)为例,:old.salary操作该行之前员工的薪水,而:new.salary表示操作该行之后员工的薪水。

# 提示:old和:new表示的表中同一行。区别是:old表示操作之前,
# 而:new表示操作之后。注意这里的冒号不能少。


下面是利用数据库的触发器可以实现安全性的检查。这里的需求是:禁止在非工作时间往员工表中插入数据。例如:今天如果是星期天就不允许在员工表上执行insert操作。


(1)创建语句级触发器dmhr.securityemp禁止在非工作时间往员工表中插入数据。

SQL> create or replace trigger dmhr.securityemp
before insert
on dmhr.employee
begin
 -- 判断当前时间是否是非工作时间
  if to_char(sysdate,'day') in ('星期六','星期日') or
     to_number(to_char(sysdate,'hh24')) not between 9 and 18 then
     --如果是在非工作时间,禁止insert操作抛出异常
     raise_application_error(-20001,'此时不允许插入员工数据');
  end if;
end;
/
# 触发器dmhr.securityemp中指定的非工作时间有两个:一个是周末;
# 另一个是早9点前和晚18点后。


(2)非工作时间在员工表上执行insert操作。

SQL> insert into dmhr.employee
(employee_id,employee_name,email,hire_date,job_id,salary,department_id) 
values(1234,'Tom','tom@126.com',sysdate,42,7000,706);
# 输出的信息如下:
[-20001]:此时不允许插入员工数据
-20001: SECURITYEMP line 9 .
已用时间: 2.673(毫秒). 执行号:0.


(3)删除触发器。

SQL> drop trigger dmhr.securityemp;



相关文章
|
8月前
|
Oracle 关系型数据库 Linux
【赵渝强老师】Oracle数据库配置助手:DBCA
Oracle数据库配置助手(DBCA)是用于创建和配置Oracle数据库的工具,支持图形界面和静默执行模式。本文介绍了使用DBCA在Linux环境下创建数据库的完整步骤,包括选择数据库操作类型、配置存储与网络选项、设置管理密码等,并提供了界面截图与视频讲解,帮助用户快速掌握数据库创建流程。
689 93
|
7月前
|
Oracle 关系型数据库 Linux
【赵渝强老师】使用NetManager创建Oracle数据库的监听器
Oracle NetManager是数据库网络配置工具,用于创建监听器、配置服务命名与网络连接,支持多数据库共享监听,确保客户端与服务器通信顺畅。
376 0
|
8月前
|
数据库
【赵渝强老师】达梦数据库实例的状态
达梦数据库实例包含NORMAL、PRIMARY和STANDBY三种模式,以及MOUNT、OPEN和SUSPEND三种状态。模式之间可在MOUNT状态下相互转换,不同状态与模式适用于数据库的启动、配置及运行需求。
412 1
|
9月前
|
存储 关系型数据库 MySQL
【赵渝强老师】MySQL数据库的多实例环境
MySQL多实例是指在一台服务器上运行多个MySQL服务,通过不同端口提供独立的数据服务。各实例共享安装程序,但使用各自的配置文件和数据文件,实现资源高效利用。本文详细介绍了如何通过“mysqld_multi”工具配置和启动多个MySQL实例,并演示了目录创建、初始化、配置文件修改及实例启动等操作步骤。
398 1
|
12月前
|
关系型数据库 MySQL 数据库
【赵渝强老师】数据库不适合Docker容器化部署的原因
本文介绍了在Docker中部署MySQL数据库并实现数据持久化的方法,同时分析了数据库不适合容器化的原因。通过具体步骤演示如何拉取镜像、创建持久化目录及启动容器,确保数据安全存储。然而,由于数据安全性、硬件资源争用、网络带宽限制及额外隔离层等问题,数据库服务并不完全适合Docker容器化部署。文中还提到数据库一旦部署通常无需频繁升级,与Docker易于重构和重新部署的特点不符。
554 19
【赵渝强老师】数据库不适合Docker容器化部署的原因
|
9月前
|
存储 关系型数据库 数据库
【赵渝强老师】PostgreSQL数据库的WAL日志与数据写入的过程
PostgreSQL中的WAL(预写日志)是保证数据完整性的关键技术。在数据修改前,系统会先将日志写入WAL,确保宕机时可通过日志恢复数据。它减少了磁盘I/O,提升了性能,并支持手动切换日志文件。WAL文件默认存储在pg_wal目录下,采用16进制命名规则。此外,PostgreSQL提供pg_waldump工具解析日志内容。
887 0
|
11月前
|
存储 关系型数据库 分布式数据库
【赵渝强老师】基于PostgreSQL的分布式数据库:Citus
Citus 是基于 PostgreSQL 的开源分布式数据库,采用 shared nothing 架构,具备良好的扩展性。它以插件形式集成,部署简单,适用于处理大规模数据和高并发场景。本文介绍了 Citus 的基础概念、安装配置步骤及其在单机环境下的集群搭建方法。
944 2
|
10月前
|
SQL 关系型数据库 MySQL
【赵渝强老师】MySQL中的数据库对象
本教程详细介绍了MySQL数据库中的常见对象,包括表、索引、视图、事件、存储过程和存储函数的创建与管理。内容涵盖表的基本操作、索引的使用、视图简化查询、事件调度功能等,并通过具体示例演示相关SQL语句的使用方法。
218 0
|
12月前
|
存储 关系型数据库 MySQL
【赵渝强老师】OceanBase数据库从零开始:MySQL模式
《OceanBase数据库从零开始:MySQL模式》是一门包含11章的课程,涵盖OceanBase分布式数据库的核心内容。从体系架构、安装部署到租户管理、用户安全,再到数据库对象操作、事务与锁机制,以及应用程序开发、备份恢复、数据迁移等方面进行详细讲解。此外,还涉及连接路由管理和监控诊断等高级主题,帮助学员全面掌握OceanBase数据库的使用与管理。
603 5
|
10月前
|
存储 Oracle 关系型数据库
【赵渝强老师】Oracle RMAN的目录数据库
Oracle RMAN默认将备份元信息存储在控制文件中,但控制文件损坏或丢失会导致恢复失败,且备份增多会使控制文件无限增长。为解决这些问题,Oracle引入了RMAN目录数据库(Catalog Database),专门用于存储RMAN备份的元信息。使用目录数据库可提升备份管理效率,支持多数据库共享、长期备份历史记录存储,并可保存RMAN脚本。本文详细介绍了如何创建目录数据库、注册目标数据库及其操作步骤。
288 0