牛新庄博士(数据库维护、优化和架构专家)拥有DB2 V5、V6、V7、V8和V9全部认证,同时他还拥有OCP、AIX、HP-UX、MQ、TSM和WebSphere等20多项国际认证。
牛新庄博士是IBM官方资深培训讲师(培训DB2、AIX、MQ、WebSphere、TSM和CICS),是中信银行、山东农信、青岛海尔等公司的资深技术顾问,曾经帮助工农商建招交六大行、联想集团、青岛海尔、云南红塔、江苏电力公司等国内很多企业做过问题诊断、性能调优和技术支持,具有丰富的理论和实践结合经验。2004年和2005年分别在上海北京成立咨询顾问公司,2008年以年薪217万被中国建设银行总行外聘为资深技术专家。
牛新庄博士拥有的奖项有:国内数据库领域最高荣誉的“2006年中国首届杰出数据库工程师”奖,首届IBM杰出软件专家奖,“2006年IT 168技术卓越”奖。
创建数据库对象
在数据库创建后,我们可以根据我们的业务需求来设计和创建数据库对象了。可以在DB2数据库中创建下列数据库对象:
● 模式
● 表
● 索引
● 序列
● 视图
● 触发器
我们可以使用图形用户界面或通过显式执行SQL语句来创建这些数据库对象。用于创建这些数据库对象的语句称为“数据定义语言(DDL)”,它们通常以关键字CREATE或ALTER作为前缀。
5.1 模式
5.1.1 模式概念
数据库中的大多数对象指定一个由两部分组成的唯一名称,如图5-1所示。第一部分(最左边的)称为限定词或模式,而第二部分(最右边的)称为简单(或未限定)名称。从句法上来说,这两部分并置成用句点分隔的单个字符串。第一次创建可以由模式名限定的任何对象(例如表、索引、视图、用户定义的数据类型、用户定义的函数、昵称、程序包或触发器)时,会根据对象名称中的限定词将该对象指定给一个特定模式。
图5-1 数据库对象名的组成
例如,图5-2说明在创建表的过程中如何将该表指定给一个特定模式。
DB2中的模式(schema)是一个已命名对象的集合,它提供一种方法来按逻辑分组这些对象。这些对象包括表、视图、索引、触发器、函数和包。模式提供了数据库中对象的逻辑类别。模式也是名称限定词;它提供一种方法来对几个对象使用相同名称,并防止对这些对象进行二义性引用。例如,使用模式名“PROD”和“DEV”很容易区分两个不同的SALES表(PROD.SALES和DEV.SALES)。模式名的最大长度为30字节,它用作分两部分的对象名的第一部分。例如,名称 CITIC.CUSTOMER。在这个示例中,CUSTOMER表的完全限定名包含模式名:CITIC,这可以在系统编目中将它与其他名为CUSTOMER的表区分开。可以把模式想象为特定对象的创建者、生成者和主人。
图5-2 创建表并将其指定给一个特定格式
如果创建对象而没有指定模式,那么对象使用您的用户名与一个隐式模式相关联(假设用户或组具有IMPLICIT_SCHEMA数据库权限,IMPLICIT_SCHEMA权限简单来说就是假设一个用户创建一个对象的时候没有使用模式,那么数据库就隐含地创建一个和用户名一样的模式,关于这个权限在13章中有详细讲解)。当SQL语句引用对象时,如果没有指定模式名,那么也会隐式地加上调用者的用户名。
5.1.2 系统模式
对于每个数据库,都创建和维护一组系统编目表。这些表包含关于数据库对象(例如表、视图、索引和包)的定义的信息以及关于用户对这些对象的访问类型的安全信息。这些表存储在SYSCATSPACE表空间中,并采用保留的系统模式名:
● SYSIBM、SYSFUN和SYSPROC:一组例程,包括函数和存储过程,其中的SYSIBM 是基本系统编目的模式(不建议直接访问它)。
● SYSCAT:一组只读的系统编目表视图,记录数据库对象的结构信息。
● SYSSTAT:一组可更新的编目视图。这些可更新的视图允许更新某些统计信息,从而模拟和测试数据库的性能,或者更新统计信息而不使用RUNSTATS实用程序。
● SYSIBMADM:一组动态性能视图,可以从该组视图中获取数据库的性能运行信息。在本书“第9章:DB2性能监控”中有关于性能视图的详细讲解和案例。
5.1.3 设置和获得当前模式
在客户端连接实例或数据库时,会话的特殊寄存器CURRENT SCHEMA包含默认的限定符,用于对特定DB2连接中发出的动态SQL语句所引用的未限定对象进行限定。它的初始值等于特殊寄存器USER中的值(运行时用户)。静态SQL语句(在默认情况下)由绑定应用程序的用户的授权ID进行限定。用户可以使用SET CURRENT SCHEMA语句修改特殊寄存器CURRENT SCHEMA的值。
可以用VALUES CURRENTSCHEMA或SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1命令获得当前的模式名。下面我们看两个使用模式的示例:
例5-1 用户= HRUSER01,具有IMPLICIT_SCHEMA权限。
命令 结果
CREATE TABLE TEST1(ID INT, NAME VARCHAR(25)) Table HRUSER01.TEST1 created
CREATE TABLE CITIC.TEST1(ID INT, NAME VARCHAR(25)) Table CITIC.TEST1 created
SET CURRENT SCHEMA='CITIC' CURRENT SCHEMA special register
set to CITIC
INSERT INTO TEST1 VALUES(1,'John Doe') Data inserted into table CITIC.TEST1
例5-2 用户= HRUSER01,没有IMPLICIT_SCHEMA权限。
命令 结果
CREATE TABLE TEST1(ID INT,
NAME VARCHAR(25)) SQL0552N "HRUSER01" does not have the privilege to perform operation "IMPLICIT CREATE SCHEMA". SQLSTATE=42502
CREATE TABLE HRUSER01.TEST1
(ID INT, NAME VARCHAR(25)) SQL0552N "HRUSER01" does not have the privilege to perform operation "IMPLICIT CREATE SCHEMA". SQLSTATE=42502
CREATE SCHEMA HRUSER01
AUTHORIZATION HRUSER01 Schema HRUSER01 created
CREATE TABLE TEST1(ID INT,
NAME VARCHAR(25)) Table HRUSER01.TEST1 created
5.1.4 模式和用户的区别
我们要把模式和用户区分开,默认情况下一个用户(用户拥有IMPLICIT_SCHEMA权限)有一个和它同名的模式,您也可以根据需要创建模式授权给某个用户。模式创建有隐式创建和显式创建两种方式。
隐式创建
如果您具有IMPLICIT_SCHEMA权限,那么可以隐式创建模式。只要具有此权限,无论您何时使用不存在的模式名创建对象,都会隐式创建一个模式。只要创建对象的用户拥有 IMPLICIT_SCHEMA权限,通常会在第一次创建模式中的数据对象时隐式创建模式。
显式创建
使用CREATE SCHEMA语句来创建模式。有关模式的信息保存在连接的数据库的系统目录表中。
要创建模式并让另一个用户成为该模式的所有者(后一个操作是可选的),您需要 SYSADM或DBADM权限。即使您不具有这两种权限中的任何一种,您也可以使用您自己的授权标识来创建模式。作为CREATE SCHEMA语句的一部分创建的任何对象的定义者是模式所有者。此所有者可以授予和撤销其他用户的模式特权。
要通过命令行来创建模式,请输入以下语句:
CREATE SCHEMA
[ AUTHORIZATION ]
其中是模式的名称。此名称在目录中已记录的模式内必须唯一,并且不能以SYS 开头。如果指定了可选的AUTHORIZATION子句,那么将成为模式所有者。如果未指定此子句,那么发出此命令的授权标识将成为模式所有者。
例5-3 下面的示例创建了agent模式并且把agent授权给db2inst1用户所有。
CREATE SCHEMA agent AUTHORIZATION db2inst1
删除模式
在删除模式之前,必须删除该模式中的所有对象或将它们移至另一个模式。当尝试 DROP语句时,该模式名必须在语句中;否则会返回错误。
要使用命令行来删除模式,请输入:
DROP SCHEMA RESTRICT
在以下示例中,删除了模式“agent”:
DROP SCHEMA agent RESTRICT
5.2 表设计考虑
所有数据都存储在数据库的表中。表由不同数据类型的一列或多列组成。数据存储在行(或称为记录)中。本节我不会过多地讲CREATE TABLE、ALTER TABLE或DROP TABLE之类的命令。这些命令您可以查SQL参考手册,本节主要讲一些和表设计相关的考虑事项,因为很多时候如果我们在建表的时候没有注意到这些,一旦系统上线,后期的调整往往非常麻烦,所以在建表之前,我们要作好规划设计。
5.2.1 选择合适的数据类型
定义列时,需要对列进行命名,定义这些列中将包含的数据的类型(称为数据类型),并定义要创建的表中每列的数据长度。DB2提供了一套丰富且灵活的数据类型。DB2附带 INTEGER、CHAR、DATE和大对象等基本数据类型。它还提供了创建用户定义的数据类型(UDT)的工具,使用户能够创建复杂的非传统的数据类型,从而适应当今复杂的编程环境。在给定的情况下,选用哪种数据类型取决于列中存储的信息的类型和范围。
内置的数据类型分为5类:数字、字符串、大对象、日期时间和XML。
用户定义的数据类型分为:单值类型、结构化类型和引用类型(一般不用)。
DB2内置的数据类型如图5-3所示。
图5-3 DB2内置的数据类型
其中,XML数据类型是DB2 V9以后版本提供的数据类型。DB2提供了XML数据类型来存储格式良好的XML文档。XML数据类型用于定义表中存储XML值的列,这些列中存储的所有XML值必须是结构良好的XML文档。引入此本机XML数据类型能够将结构良好的XML文档以其本机分层格式存储在数据库中其他关系数据旁边。
XML列中的值存储为与字符串数据类型不同的内部表示。要在XML数据类型的列中存储XML数据,需要使用XMLPARSE函数对数据进行转换。可以使用XMLSERIALIZE函数将XML数据类型的值转换为XML文档的串行化字符串值。DB2还提供了许多其他的内置函数来操纵XML数据类型。
我们在创建表时为列选择数据类型时一定要注意下面几点:
● 要根据业务需求选择合适的数据类型,避免出现数据类型转换。例如,我曾经看到有的客户使用字符来存放日期、时间戳,最后我们还要在程序中使用日期转换函数to_date作数据类型转换,这会对应用程序带来性能影响。
● 根据需求选择合适的长度。例如,用一个字段empno来存储员工号,用SMALL INT就可以满足,但是如果我们用INT就会造成两个字节的浪费。
● 如果某个字段的内容都是数字,建议大家选用整数而不要选用CHAR。一个占用4字节的INT类型字段就可以表达到4294967295,如果使用CHAR型则至少需要10个字节。一个占用8字节LONG INT类型字段就可以表达到18446744073709551615,如果使用CHAR型至少需要20个字节。
● CHAR和VARCHAR的选择,如果一列的数据有变化,但是变化不大时,而我们又追求性能,建议使用CHAR类型,因为VARCHAR的读取性能要分两个步骤,先读长度再读数据比CHAR的性能要弱些。
● LONG VARCHAR、BLOB、CLOB和CBLOB数据类型的选择,这些大对象数据类型的读取是不经过内存而直接读取的,所以可根据情况看是否能够用VARCHAR字段代替。
● 如果使用大对象数据类型,考虑是否对该大对象列记录日志NOT LOGGED。
● 考虑把大对象数据列单独存放在独立的表空间,和索引数据分隔存放。
下面让我们看看列在磁盘上是如何布局的。如果您创建了一个只有定长列的表,将严格按照 CREATE语句中指定的顺序安排它们,如图5-4所示。
CREATE TABLE TESTORD(COL1 INT, COL2 CHAR(5), COL3 DEC(10,2), COL4 FLOAT)
图5-4 定长列的表在磁盘上布局
如果表拥有变长列(如VARCHAR),列仍然按照CREATE TABLE语句中指定的顺序排序,但可变数据本身在行的末尾,如图5-5所示。
CREATE TABLE TESTORD(COL1 INT, COL2 VARCHAR(5), COL3 DEC(10,2))
图5-5 拥有变长列的表在磁盘上的布局
如果表有长字段,它将不随每行直接插入。因为行的长度受页大小限制(4KB到32KB),所以行只有一个指向长字段的指针,而将长字段与行分开放置在数据库页中,如图5-6所示。
CREATE TABLE TESTORD(COL1 INT, COL2 CLOB(100 K), COL3 DEC(10,2))
图5-6 拥有长字段的表在磁盘上的布局
5.2.2 选择合适的约束类型
在任何业务中,数据通常必须符合特定限制或业务规则。例如,职员编号、银行支票号必须是唯一的。数据库管理器提供了约束作为强制实施这种规则的方法。约束是用于业务需求的规则。DB2提供了下列5种类型的约束:
NOT NULL约束
NOT NULL约束防止在列中输入空值。NOT NULL约束是这样一种规则,它防止在表的一列或多列中输入空值。数据库中使用空值来表示未知状态。默认情况下,随数据库管理器一起提供的所有内置数据类型都支持空值的存在。但是,一些业务规则可能要求必须始终提供值(例如,乘飞机时必须提供紧急联系人信息)。NOT NULL约束用于确保决不会为给定表列指定空值。为特定列定义NOT NULL约束后,尝试在该列中放入空值的任何插入或更新操作将失败。
唯一约束
唯一约束确保一组列中的值对于表中的所有行都是唯一的,且不为空。在唯一约束中指定的列必须定义为NOT NULL。唯一约束(也称为唯一键约束)是这样一种规则,它禁止表的一列或多列中出现重复值。唯一键和主键是受支持的唯一约束。例如,可对供应商表中的供应商标识定义唯一约束以确保不会对两个供应商指定同一供应商标识。唯一约束确保一组列中的值对于表中的所有行都是唯一的,且不为空。在唯一约束中指定的列必须定义为NOT NULL。数据库管理器使用唯一索引在对唯一约束的各列进行更改时强制键的唯一性。例如,DEPARTMENT表中的典型唯一约束可以是:部门号是唯一的,且不为空。
图5-7显示了当表存在唯一约束时,阻止将重复的记录添加到该表。
数据库管理器在插入和更新操作期间强制执行此约束,以确保数据完整性。表可以有任意数目的唯一约束,但最多将一个唯一约束定义为主键。对于同一组列,表不能有多个唯一约束。