关于数据库设计中主键问题的思考

关于数据库设计中主键问题的思考
关于数据库设计中主键问题的思考

关于数据库设计中主键问题的思考

文章摘要:数据库主键在数据库中占有重要地位。主键的选取策略决定了系统是否可靠、易用、高效。本文探讨了数据库设计过程当中常见的主键选取策略,并剖析了其做主键的优缺点,提出了相应的解决问题的方法。

关键字:自增标识GUID COMB

在基于关系型数据库设计时候,通常要为每张表指定一个主键,所谓主键就是能够唯一标识表中某一行记录的属性或属性组,一个表只能有一个主键,但可以有多个候选索引。因为主键可以唯一标识某一行记录,所以可以确保执行数据更新、删除、修改时不出现错误。当然,其它字段可以辅助我们在执行这些操作时消除共享冲突,不是本文讨论的重点,不再赘述。主键除了上述作用外,常常与外键构成参照完整性约束,防止出现数据不一致。所以数据库在设计时,主键起到了很重要的作用。常见的数据库主键选取方式有:自动增长式、手动增长式、UniqueIdentifier、联合式(复合式)、时间序列+随机数式、“COMB(Combine)”类型。

一、自动增长式

很多数据库设计者喜欢使用自动增长型字段,因为它使用简单。自动增长式允许我们在向数据库添加数据时,不考虑主键的取值,记录插入后,数据库系统会自动为其分配一个值,确保绝对不会出现重复。如果使用SQL Server数据库的话,我们还可以在记录插入后使用@@IDENTITY全局变量获取系统分配的主

键值。

尽管自动增长式字段会省掉我们很多繁琐的工作,但使用它也存在潜在的问题,那就是在数据缓冲模式下,很难预先填写主键与外键的值。假设有主辅两张表:

Order(OrderID, OrderDate) 订单表

OrderDetial(OrderID, LineNum, ProductID, Price) 订单明细表Order 表中的OrderID是自动增长型的字段。假设现在需要我们录入一张订单,包括在Order表中插入一条记录以及在OrderDetail表中插入若干条记录。因为Order表中的OrderID是自动增长型的字段,那么我们在记录正式插入到数据库之前无法事先得知它的取值,只有在更新后才能知道数据库为它分配的是什么值。这会造成以下矛盾发生:

首先,为了能在OrderDetail的OrderID字段中添入正确的值,必须先更新Order表以获取到系统为其分配的OrderID值,然后再用这个OrderID填充OrderDetail表的OrderID列。最后更新OderDetail表。但是,为了确保数据的一致性,Order与OrderDetail在更新时必须在事务模式下进行的,即要么两张表同时同时更新成功、要么全部失败,显然它们是相互矛盾的。

其次,当我们需要在多个数据库间进行数据的复制时(SQL Server的数据分发、订阅机制允许我们进行库间的数据复制操作),自动增长式字段可能造成数据合并时的主键冲突及表关联关系的丢失。设想一个数据库中的Order表向另一个库中的Order

表复制数据库时,OrderID到底该不该自动增长呢?如果自动增长,其子表OrderDetial的关联关系会丢失,如果不增长就会和现有数据主键重复,是不是很矛盾呢?

再次,自增量的值都是需要在系统中维护一个全局的数据值,每次插入数据时即对此次值进行增量取值。当在产生唯一标识的并发环境中,每次的增量取值都必须为此全局值加锁解锁以保证增量的唯一性。造成并发瓶颈,降低查询性能。

还有当数据表足够大或频繁的更改和插入操作导致主键类型值超出范围,这种情况一般很少碰到,但也是我们进行数据表设计时必须考虑的一个问题

二、手动增长型字段

既然自动增长型字段会带来如此的麻烦,我们不妨考虑使用手动增长型的字段,也就是说主键的值需要自己维护,通常情况下需要建立一张单独的表存储当前主键键值。为了叙述上的方便仍然利用上面的例子进行阐述,新建一张表叫IntKey,包含两个字段,KeyName以及KeyValue。就像一个HashTable,给一个KeyName,就可以知道目前的KeyValue是什么,然后手工实现键值数据递增。在SQL Server中可以编写这样一个存储过程,让取键值的过程自动进行。代码如下:

CREATE PROCEDURE [GetKey]

@KeyName char(10),

@KeyValue int OUTPUT

AS

UPDATE IntKey SET @KeyValue = KeyValue = KeyValue + 1 WHERE KeyName = @KeyName

GO

这样,通过调用存储过程,我们可以获得最新键值,确保不会出现重复。若将OrderID字段设置为手动增长式字段,我们的程序可以由以下几步来实现:首先调用存储过程,获得一个OrderID,然后使用这个OrderID填充Order表与OrderDetail表,最后在事务机制下对两表进行更新。

使用手动增长式字段作为主键在进行数据库间数据复制时,可以确保数据合并过程中不会出现键值冲突,只要为不同的数据表分配不同的主键取值段就行了。但是,使用手动增长型字段会增加网络的负担,必须通过增加一次数据库访问来获取当前主键键值,这会增加网络和数据库的负载,当处于一个低速或断开的网络环境中时,这种做法会有很大的弊端。同时,手工维护主键还要考虑并发冲突等种种因素,这更会增加系统的复杂程度。三、使用UniqueIdentifier

SQL Server为我们提供了UniqueIdentifier数据类型,并提供了一个生成函数NEWID( ),使用NEWID( )可以生成一个唯一的UniqueIdentifier。UniqueIdentifier在数据库中占用16个字节,出现重复的概率几乎为0,号称全球唯一标识。我们经常从注册表或WINDOWS程序出现错误需要调试时看到类似

768427bf-9b37-4776-97ca-000365e160d5或

{45F0EB02-0727-4F2E-AAB5-E8AEDEE0CEC5} 的东西实际上就是一个UniqueIdentifier,Windows用它来做COM组件以及接口的标识,防止出现重复。在.NET中UniqueIdentifier称之为GUID(Global Unique Identifier)。在C#中可以使用如下命令生成一个GUID:

Guid u = System.Guid.NewGuid();

对于上面提到的Order与OrderDetail的程序,如果选用UniqueIdentifier作为主键的话,我们完全可以避免上面提到的增加网络RoundTrip的问题。通过程序直接生成GUID填充主键,不用考虑是否会出现重复。但是UniqueIdentifier 字段也存在严重的缺陷:首先,它的长度是16字节,是整数的4倍长,会占用大量存储空间。更为严重的是,UniqueIdentifier的生成毫无规律可言,也就是说是无序的,要想在上面建立索引(绝大多数数据库在主键上都有索引)是一个非常耗时的操作。有人做过实验,当数据表记录比较大的时,在不同的数据量级别上插入同样的数据量,使用UniqueIdentifier型数据做主键要比使用Integer型数据慢,且还没有考虑到表关联的情况,出于效率考虑,尽可能避免使用UniqueIdentifier型数据库作为主键值,但随着现代计算机计算速度越来越快,在中小型项目中使用UniqueIdentifier式主键也是一个选项。

四、使用业务字段联合主键

基于DEPHI和POWERBUILDER等数据库工具开发C/S系统的数据库设计人员,习惯上用有业务意义的字段组合成复合主键做数据表主键。使用业务主键当然有其与生俱来的好处,一般情况下数据库系统会在默认条件下建立聚簇索引,而且这个聚簇索引基于主键升序排列,当数据量比较小时,我们感觉不到这种差别,当数据量比较大时,这种基于主键定义的聚簇索引的优势就显现出来,这就使得数据表在每次存取数据时按照索引准确确认数据插入或更新的磁盘物理位置,减少磁头寻址时间,从而提高数据库性能,而且能够从业务意义上保证数据的完整性,增加程序的可靠性。但是基于业务字段的联合索引,当业务字段选用比较多时会占用比较多的磁盘空间,而且索引页会占用更多的内存页面,从而导致查询命中率降低;另外使用业务主键,当涉及到主键数据的修改时,要在编程过程中记录新值和原值的关系表,在更新时又要进行新值和原值的比对,增加编写程序的复杂度。

五、时间序列+随机数主键

采用精确到毫秒甚至钠秒级的时间和一个随机产生的两位数做主键,如200911282311528+两位随机数,不失为解决主键问题的一个有效办法。这样产生的主键既避免了UniqueIdentifier 型字段做主键时的无序,又能有效避免自动增长型主键带来的诸如复制和数据导入的麻烦。但在使用用户众多的网络实时系统中,在时间和空间上仍然不能保证唯一性的问题。

六、使用“COMB(Combine)”类型

既然上面五种主键类型选取策略都存在各自的缺点,那么到底有没有好的办法加以解决呢?答案是肯定的。通过使用COMB 类型(数据库中没有COMB类型,它是Jimmy Nilsson在他的“The Cost of GUIDs as Primary Keys”一文中设计出来的),可以在以上众多的主键策略之间采用中庸之道,找到一个很好的平衡点。COMB数据类型的基本设计思路是这样的:既然UniqueIdentifier 数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么我们能不能通过组合的方式,保留UniqueIdentifier的前10个字节,用后6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与UniqueIdentifier组合起来,在保留UniqueIdentifier的唯一性的同时增加了有序性,以此来提高索引效率。也许有人会担心UniqueIdentifier减少到10字节会造成数据出现重复,其实不用担心,后6字节的时间精度可以达到1/300秒,两个COMB类型数据完全相同的可能性是在这1/300秒内生成的两个GUID前10个字节完全相同,这几乎是不可能的!在SQL Server中用SQL命令将这一思路实现出来便是:DECLARE @aGuid UNIQUEIDENTIFIER

SET @aGuid = CAST(CAST(NEWID() AS BINARY(10))

+ CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER) 经过测试,使用COMB做主键比使用INT做主键,在检索、插入、更新、删除等操作上仍然显慢,但比Unidentifier类型要快

上一些。除了使用存储过程实现COMB数据外,我们也可以使用C#生成COMB数据,这样所有主键生成工作可以在客户端完成。C#代码如下:

//================================================ /**////

/// 返回GUID 用于数据库操作,特定的时间代码可以提高检索效率

///

/// COMB (GUID 与时间混合型) 类型GUID 数据

public static Guid NewComb()

{

byte[] guidArray = System.Guid.NewGuid().ToByteArray(); DateTime baseDate = new DateTime(1900,1,1);

DateTime now = DateTime.Now;

// Get the days and milliseconds which will be used to build the byte string

TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks); TimeSpan msecs = new TimeSpan(now.Ticks - (new DateTime(now.Year, now.Month, now.Day).Ticks));

// Convert to a byte array

// Note that SQL Server is accurate to 1/300th of a millisecond so we

divide by 3.333333

byte[] daysArray = BitConverter.GetBytes(days.Days);

byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds/3.333333)); // Reverse the bytes to match SQL Servers ordering

Array.Reverse(daysArray);

Array.Reverse(msecsArray);

// Copy the bytes into the guid

Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);

Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);

return new System.Guid(guidArray);

}

//================================================ /**////

/// 从SQL SERVER 返回的GUID 中生成时间信息

///

/// 包含时间信息的COMB

/// 时间

public static DateTime GetDateFromComb(System.Guid guid)

{

DateTime baseDate = new DateTime(1900,1,1);

byte[] daysArray = new byte[4];

byte[] msecsArray = new byte[4];

byte[] guidArray = guid.ToByteArray();

// Copy the date parts of the guid to the respective byte arrays. Array.Copy(guidArray, guidArray.Length - 6, daysArray, 2, 2); Array.Copy(guidArray, guidArray.Length - 4, msecsArray, 0, 4);

// Reverse the arrays to put them into the appropriate order Array.Reverse(daysArray);

Array.Reverse(msecsArray);

// Convert the bytes to ints

int days = BitConverter.ToInt32(daysArray, 0);

int msecs = BitConverter.ToInt32(msecsArray, 0);

DateTime date = baseDate.AddDays(days);

date = date.AddMilliseconds(msecs * 3.333333);

return date;

}

纵上述六种主键选取策略,笔者认为使用“COMB (Combine)”类型做主键是比较恰当的主键应用策略,但在实际使用过程中要根据客观实践、因时因事选取适当的主键,切不可生搬硬套、弄巧成拙。

参考文献:

1、《系统分析师教程》张友生主编

2、《中文版SQL Server 2000开发与管理应用实例》邹建主编

3、《数据库中使用自增量字段与Guid字段主键的性能对比》作者不详

4、《小议数据库主键选取策略》作者不详

数据完整性约束-主键约束

数据完整性约束(一) —— SQL Server 2016数据库及应用

由于数据库中的数据是从外界输入的,然而数据的输入由于种种原因,会发生输入无效或错误信息,数据的完整性正是为了保证输入的数据符合规定而提出的。 数据完整性分为四类: 实体完整性、域完整性、参照完整性和用户自定义完整性。

1. 实体完整性: 实体完整性要求如果属性A是关系R的主属性,则属性A不能取空值。实体完整性用于保证关系数据库表中的每条记录都是唯一的,建立主键的目的就是为了实现实体完整性。 2. 域完整性: 用来保证数据的有效性,它可以限制录入的数据与数据类型是否一致,规定字段的默认值,设置字段是否可以为空,域完整性可以确保不会输入无效的数据。

3. 参照完整性:参照完整性是基于外键的,如果表中存在外键,则外键的值必须与主表中的某条记录的被参照列的值相同,参照完整性用于确保相关联表之间的数据保持一致。当添加、删除或修改数据表中记录时,可以借助于参照完整性来保证相关表之间数据的一致性。 ClassNo ClassName Specialty EnterYear Dno 0111801 网络3181 计算机网络技 术 2018 D01 0121901 软件3191 软件技术 2019 D01 主键 Class Sno Sname Sex Birth ClassNo s011180106 陈骏 男 2000/7/5 0111801 s012190118 陈天明 男 2000/7/18 0121901 主键 外键 Student

4. 用户自定义完整性: 用户自定义完整性约束就是针对某一具体关系数据库的约束条件,它反映某一具体应用所涉及的数据必须满足的语义要求。 如何实现数据完整性,可以通过为表的字段设置约束来保证表中数据完整性。

数据库主键和外键的作用

数据库主键和外键的作用 首先介绍一下什么是主键、什么是外键。 1 什么是主键外键 学生表(学号,姓名,性别,班级) ? 学号是一个主键 课程表(课程号,课程名,学分) 课程号是一个主键 成绩表(学号,课程号,成绩) 学号和课程号的属性组构成一个主键 成绩表中的学号不是成绩表的主键,不过是学生表的主键,成绩表的外键,同理课程号也是成绩表的外键 定义:如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键 以一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表 2 外键的作用 外键用于保持数据一致性,完整性 主要目的是控制存储在外键表中的数据 3 主键的设计原则 1)主键应当是对用户没有意义的 2)主键应该是单列的,以提高连接和筛选操作的效率 复合键的使用通常出于两点考虑: a)主键应当具有意义-----这为认为的破坏数据库提供了方便 b)在描述多对多关系的连接表中可以使用两个外部键作为主键------该表可能成为其他从表的主表,并成为从表的主键的一部分,使得之后的从表包含更多的列 3)永远不要更新主键 4)主键不应该包含动态变化的数据(时间戳等) 5)主键应当由计算机自动生成 4 数据库主键选取策略 建立数据库的时候,需要为每张表指定一个主键(一个表只能有一个主键,但是可以有多个候选索引) 常见的主键选取方式有: 1)自动增长型字段 自动增长型主键会省略很多繁琐的工作,但在数据缓冲模式下,不能预先填写主键与外键的值 Order(OrderID,OrderDate)? //主键OrderID是自动增长型字段 OrderDetail(OrderID,LineNum,ProductID,Price)

约束语法

SQL Server 2000支持下列五类约束:(1)DEFAULT约束(默认约束):当向数据库表中插入数据时,如果没有明确的提供输入值时,SQL S自动为该列输入指定值。(2)CHECK约束(检查约束):通过逻辑表达式判断限制插入到列中的值。(3)PRIMARY KEY约束(主键约束):不允许数据库表在指定列上具有相 同的值,且不允许有空值。(4)FOREIGN KEY约束(外键约束):定义数据库 表中指定列上插入或更新的数值必须在另一张被参照表中的特定列上存在。(5)UNIQUE约束(惟一约束):不允许数据库表在指定列上具有相同的值,但允许 有空值。约束也被分为列约束和表约束两类。列约束是指只对某一列起作用的约束。当一个约束中包含了数据库表中一个以上的列时,称为表约束。 24、约束的创建约束可以通过使用CREATE TABLE命令创建。具体语法如下: CREATE TABLE table_name (column_name data_type (NULL | NOT NULL)[[CONSTRAINT constraint_name]{PRIMARY KEY [CLUSTERED | NONCLUSTERED] | UNIQUE [CLUSTERED | NONCLUSTERED] | [FOREIGN KEY] REFERENCES ref_table [(ref_column)] | DEFAULT constant_expression | CHECK(logical_expression)}][,...]) 其中,各参数的意义 为: table_name:创建约束的表名称 column_name:创建约束的列的名 称 data_type:所在列的数据类型 constraint_name:新建约束的名称 [例题37] 在tsinghua数据库中创建一张用于教师信息管理的表teachers,表中包括的教师信息分别为:教师编号、教师姓名、性别、出身年月、所在系代号、职称、办公室电话号码、科研方向以及工作状态,在创建时定义有列约束和表约束。具体命令如下: use tsinghua CREATE TABLE tsinghua.dbo.teachers (TeacherID int NOT NULL, name nvarchar(5) NOT NULL, gender nchar(1) NULL, birthday datetime NULL, DeptCode tinyint NOT NULL, Title nvarchar(5) NULL, TelCode char(8) NOT NULL, aspect nvarchar(200) NULL, status nvarchar(5) NOT NULL CONSTRAINT DF_Status DEFAULT(' 在职'), CONSTRAINT PK_Teacher PRIMARY KEY CLUSTERED(TeacherID), CONSTRAINT FK_DeptCode FOREIGN KEY (DeptCode) REFERENCES dbo.departments(DeptCode), CONSTRAINT CK_TelCode CHECK(TelCode LIKE '627[0-9][0-9][0-9][0-9][0-9]'),) go 在这个例子中,用户可以看到我们使用的约束类型依次为非空约束、默认约束、主键约束、外键约束和检查约束。在结果显示窗口中可以看到错误提示: 服务器: 消息 1767,级别 16,状态 1,行 2 外键 'FK_DeptCode' 引用了无效的表 'dbo.departments'。服务器: 消息 1750,级别 16,状态 1,行 2 未能创建约束。请参阅前面的错误信息。 这是由于还没有在数据库tsinghua中创建外键约束FK_DeptCode所需表departments,用户可以通过下面指令先创建表departments: CREATE TABLE tsinghua.dbo.departments (DeptCode tinyint NOT NULL Primary Key, DeptName nchar(20) NOT NULL, TelCode char(8) NULL) go

实验七完整性约束的创建

实验七完整性约束的创建 一、实验目的 理解数据库完整性约束的概念,掌握SQL Server 2008的完整性约束的类型及相应的创建技术。 二、实验内容 1、定义和管理主键约束。 2、定义和管理唯一性约束。 3、定义和管理检查约束。 4、定义和管理外键约束。 5、定义和管理默认值约束。 三、实验指导 在关系数据库中,实体完整性约束、参照完整性约束和域完整性约束是必须满足的完整性约束条件。在SQL Server中,通过建立“约束”等措施来实现数据完整性约束,约束包括:主键(PRIMARY KEY)约束、唯一性(UNIQUE)约束、检查(CHECK)约束、默认值(DEFAULT)约束和外键(FOREIGN KEY)约束。约束的建立可以通过对象资源管理器进行操作,也可以利用T-SQL语句进行设置。 (一)主键(PRIMARY KEY)约束 主键约束指在表中定义一个主键来唯一标识表中每一行数据。 1、在SQL Server Management Studio中设置和修改主键 在表设计器中,单击要定义为主键的列的行选择器(如果要选择多列,在单击其他列的行选择器时按住Ctrl键)。然后右键单击该列的行选择器,选择“设置主键”命令,自动创建名为“PK_”(后跟表名)的主键索引。如图7.1所示。 2、利用T-SQL语句定义和修改主键 实验7.1 在教学管理数据库JXGL中创建学生表S的同时定义主键。 在数据库引擎查询文档中输入以下语句: USE JXGL GO CREATE TABLE S (

Sno char(8) PRIMARY KEY, Sname char(8), Sex char(2), Sage smallint, Sdept varchar(50) ) GO 注意:如果要设置多列的组合为主键,需要把主键定义为表级完整性约束。 图7.1 利用表设计器管理主键 实验7.2 在定义数据表S时没有定义主键,则需要添加主键。 在数据库引擎查询文档中输入以下语句: USE JXGL GO ALTER TABLE S ADD CONSTRAINT PK_Sno PRIMARY KEY clustered(Sno) GO 单击“执行”按钮则执行该程序段,这样就创建了名字为PK_Sno的主键。(二)唯一性(UNIQUE)约束

关于数据库中的主键的自动增长

Mysql、SqlServer、Oracle主键自动增长的设置 1、把主键定义为自动增长标识符类型 在mysql中,如果把表的主键设为auto_increment类型,数据库就会自动为主键赋值。例如: create table customers(id int auto_increment primary key not null, name varchar(15)); insert into customers(name) values("name1"),("name2"); 2、在MS SQLServer中,如果把表的主键设为identity类型,数据库就会自动为主键赋值。例如: create table customers(id int identity(1,1) primary key not null, name varchar(15)); insert into customers(name) values("name1"),("name2"); identity包含两个参数,第一个参数表示起始值,第二个参数表示增量。 3、Oracle列中获取自动增长的标识符 在Oracle中,可以为每张表的主键创建一个单独的序列,然后从这个序列中获取自动增加的标识符,把它赋值给主键。 例如一下语句创建了一个名为customer_id_seq的序列,这个序列的起始值为1,增量为2。方法一、 create sequence customer_id_seq INCREMENT BY 1 -- 每次加几个

START WITH 1 -- 从1开始计数 NOMAXVALUE -- 不设置最大值 NOCYCLE -- 一直累加,不循环 CACHE 10; 一旦定义了customer_id_seq序列,就可以访问序列的curval和nextval属性。curval:返回序列的当前值 nextval:先增加序列的值,然后返回序列值 create table customers(id int primary key not null, name varchar(15)); insert into customers values(customer_id_seq.curval, "name1"),(customer_id_seq.nextval, "name2"); 方法二、或者通过存储过程和触发器: 1、通过添加存储过程生成序列及触发器: create or replace PROCEDURE "PR_CREATEIDENTITYCOLUMN" (tablename varchar2,columnname varchar2) as strsql varchar2(1000); begin strsql := 'create sequence seq_'||tablename||' minvalue 1 maxvalue 999999999999999999 start with 1 increment by 1 nocache'; execute immediate strsql; strsql := 'create or replace trigger trg_'||tablename||' before insert on '||tablename||' for each row begin select seq_'||tablename||'.nextval into :new.'||columnname||' from dual; end;'; execute immediate strsql; end;

列级约束与表级约束

列级约束与表级约束 在SQL Server中有5种约束: 主键约束(primary key constraint) 唯一性约束(unique constraint) 检查约束(check constraint) 缺省约束(default constraint) 外部键约束(foreign key constraint) 在SQL SERVER中, (1)对于基本表的约束分为列约束和表约束 约束是限制用户输入到表中的数据的值的范围,一般分为列级约束与表级约束。 列级约束有六种:主键Primary key、外键foreign key 、唯一unique、检查checck、默认default 、非空/空值not null/ null 表级约束有四种:主键、外键、唯一、检查 列约束是对某一个特定列的约束,包含在列定义中,直接跟在该列的其他定义之后,用空格分隔,不必指定列名; 表约束与列定义相互独立,不包括在列定义中,通常用于对多个列一起进行约束,与列定义用’,’分隔,定义表约束时必须指出要约束的那些列的名称。完整性约束的基本语法格式为: [ CONSTRAINT <约束名> ] <约束类型> 约束名:约束不指定名称时,系统会给定一个名称。 (2)列级约束与表级约束的区别 如果完整性约束涉及到该表的多个属性列,必须定义在表级上,否则既可以定义在列级也可以定义在表级。 简而言之: 列级约束:列级约束是行定义的一部分,只能应用于一列上。 表级约束:表级约束是独立于列的定义,可以应用在一个表中的多列上。 (3)列级约束与表级约束在SQL中的用法(即如何在SQL中定义约束) 在创建表时定义约束: CREATE TABLE table_name ({ -------列级约束定义 |column_name AS computed_column_expression -------计算列定义 | ------表级约束定义 }[,….n] )

oracle主键的设置方法

主键: 1.主键约束:一个表只能有一个主键约束。主键可以是单个字段,也可以是多个字段。无论是哪种情况,其所有字段都是NOT NULL。 2.Unique约束:一个表可以有多个Unique约束,Unique的字段可以为NULL。 3.主键与Unique:不同点在于一个表只能有一个主键约束,但是可以有多个Unique约束;主键所有字段都是not null,unique可以是 null;相同点在于都能保证唯一性。 4.主键、Unique与索引:主键约束与Unique约束默认会成为索引。当主键和Unique有多个字段时,有索引前缀性问题,即where语 句中的条件必须有主键或者unique的第一个字段,否则不会使用索引。 5. 外键与主键、Unique:外键必须为另外一张表(父表)的主键或者唯一索引。如果要添加记录,而父表中没有则报错。反之,如 果要删除父表中的记录,而子表中有记录,也会报错。但是如果在创建外键约束时,如果使用on delete cascade,则删除父表中数据时 ,不报错而直接把子表关联的数据删除。 如果要删除父表,则需要加上cascade constraints,此时子表的foreign key被去除,表中记录保持不变。 外键: 外键是该表是另一个表之间联接的字段 外键必须为另一个表中的主键 外键的用途是确保数据的完整性。它通常包括以下几种: 实体完整性,确保每个实体是唯一的(通过主键来实施). oracle主键的设置方法有2种: 一种是设置自增长主键,另一种是生成唯一序列; 1.自增长主键 SQL> create table Prim_key_Increase_Test( 2 id number(10) primary key, 3 name varchar2(30) 4 ); 表已创建。 SQL> create sequence Prim_key_Incre_Sequence 2 minvalue 1 3 nomaxvalue 4 start with 1 5 increase by 1 6 nocycle 7 nocache; increase by 1 * 第5 行出现错误: ORA-00933: SQL 命令未正确结束 SQL> 5

主键、索引等的区别

键、索引、约束及其区别 今天下午刚好没事,把一些基础性的概念理顺一下,存档,省的麻烦,嘿嘿 一.索引 1.什么是索引? 索引是对数据库表中一列或多列的值进行排序的一种结构。 在关系型数据库中,索引是一种与表有关的数据库结构,是事实存在的。 它可以使对于表的select等等操作更加快速,相当于一本书的目录。 对于一张表,如果我们想要找到某一列符合特定值的记录,第一种方法是全表搜索,匹配,然后把所有符合的记录列出,但是这样做会消耗大量数 据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然 后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相 当于页码)快速找到表中对应的记录。 索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。由此可 知,索引是要消耗数据库空间的。 并非所有的数据库都以相同的方式使用索引。作为通用规则,只有当经常查询索引列中的数据时,才需要在表上创建索引。索引占用磁盘空间,并 且降低添加、删除和更新行的速度。在多数情况下,索引用于数据检索的速 度优势大大超过它的不足之处。但是,如果应用程序非常频繁地更新数据或 磁盘空间有限,则可能需要限制索引的数量。 可以使用单列作为索引,也可以使用多列联合作为索引。 2.索引的优缺点 优点: (1)大大加快数据的检索速度; (2)创建唯一性索引,保证数据库表中每一行数据的唯一性; (3)加速表和表之间的连接; (4)在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排 序的时间。 缺点: (1)索引需要占物理空间。 (2)当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。 建立索引时的注意事项: (1)考虑已在表上创建的索引数量。最好避免在单个表上有很多索引 (2)检查已在表上创建的索引的定义。最好避免包含共享列的重叠索引 (3)检查某列中唯一数据值的数量,并将该数量与表中的行数进行比较。 比如如果有1000w记录,某字段为性别,只有男,女。也就是说一半 的记录都是重复的,这样就要考虑是否还有必要建立索引了。 3.一些索引类别 (1)普通索引 也即不加任何限制的索引。可通过以下语句理解。 create table zjj_temp_1 (id number(10),first_name char(10),last_name char(10),age number(3),val number(10,2));

主键,外键等约束详解实例

1、--创建表 create table tb_Dept ( Deptid char(2)Primary key, DeptName char(16)Not Null ) 2、--外键约束 create table tb_Student ( Studid char(10)Primary key, Studname char(8)Not null, Deptid char(2)Not null, Constraint FK_DeptID Foreign Key(Deptid) References Tb_Dept(DeptID) ) 3、--外键约束简化形式,必须要求tb_Dept表中DeptID为主键,且数值类型相同create table Tb_Student ( StudId char(10)Primary key, StudName char(8)Not null, DeptID char(2)not null References Tb_Dept ) 4、--创建表,无主键 create table Tb_Class ( ClassID char(8)not null, ClassName varchar(30)not null, DeptId char(2)not null, ClassStuNumber int ) 5、--创建表,同时定义主键 create table Tb_Class ( classid char(8)not null, ClassName varchar(30)not null, DeptID char(2)not null, ClassStuNumber int constraint PK_ClassID Primary key (ClassID,ClassName) ) 6、--新增主键 Alter table Tb_class ADD Constraint PK_ClassID primary key(Classid) 7、--删除主键 Alter table tb_Class Delete Constraint PK_ClassID Primary key(ClassID) 8、--外键级联更新,删除,简化形式 Create table tb_student (

数据库基笔记

一.数据库初始 1.需求分析 (1).优良的数据库设计 减少数据冗杂、避免数据维护异常、节约储存空间、高效访问 (2).设计流程 需求分析(数据--属性--两者各自特点) 逻辑设计(ER图逻辑建模) 物理设计(依据各数据库特点) 维护优化(新建、索引优化、大表拆分) (3).为何需求分析与内容 都是什么数据、特点、数据周期 实体及其间的关系(1v1、1Vn、nVn)、实体包含的属性、怎样标识唯一个体注:永久与不永久储存、分表与分库储存、归档与清理 2.逻辑设计 (1).ER图 矩形:实体集 菱形:关系集 椭圆:属性 线段:图像间连接 (2).设计范式(第一、第二、第三、BC) 第一范式(1NF):表中所有字段都是单一属性,不可再分,也就是说都是二维表,如用户信息不可再分为姓名与电话

第二范式(2NF):数据库表中不存在非关键字短发对任一候选关键字段的部分函数依赖。(部分函数依赖存在于组合关键字中:多个属性组合起来确定唯一物品)如 商品名称与供应商为组合关键字,但供应商决定了其电话,商品决定了价格等,故而但关键字的一定符合2NF,有组合关键字则不一定 第三范式(3NF):在2NF基础上,数据表中不存在非关键字段对任意候选关键字段的传递函数依赖。如 商品名称——分类——分类描述,即分类描述对商品名称有传递函数依赖 BC范式:在3NF基础上,数据库表中不存在任何字段对任一候选关键字段的传递函数依赖,即复合关键字间也不可有函数依赖。 (3).操作异常: 由于实体间有依存关系 (插入异常--更新异常、删除异常) (4).数据冗杂: 相同数据多次出现或可由其它列计算得到 3.物理设计 (1).做什么 选择合适数据库管理系统----定义数据库与表及字段的命名规范----根据所选的

SQL的主键和外键约束

SQL的主键和外键约束 SQL的主键和外键的作用: 外键取值规则:空值或参照的主键值。 (1)插入非空值时,如果主键表中没有这个值,则不能插入。 (2)更新时,不能改为主键表中没有的值。 (3)删除主键表记录时,你可以在建外键时选定外键记录一起级联删除还是拒绝删除。 (4)更新主键记录时,同样有级联更新和拒绝执行的选择。 简而言之,SQL的主键和外键就是起约束作用。 关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键。 比如: 学生表(学号,姓名,性别,班级) 其中每个学生的学号是唯一的,学号就是一个主键; 课程表(课程编号,课程名,学分) 其中课程编号是唯一的,课程编号就是一个主键; 成绩表(学号,课程号,成绩) 成绩表中单一一个属性无法唯一标识一条记录,学号和课程号的组合才可以唯一标识一条记录,所以,学号和课程号的属性组是一个主键。

成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键;同理,成绩表中的课程号是课程表的外键。 定义主键和外键主要是为了维护关系数据库的完整性,总结一下: 一、主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。 外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。比如,A 表中的一个字段,是B表的主键,那他就可以是A表的外键。 二、主键、外键和索引的区别 定义: 主键--唯一标识一条记录,不能有重复的,不允许为空 外键--表的外键是另一表的主键, 外键可以有重复的, 可以是空值 索引--该字段没有重复值,但可以有一个空值 作用: 主键--用来保证数据完整性 外键--用来和其他表建立联系用的 索引--是提高查询排序的速度 个数: 主键--主键只能有一个 外键--一个表可以有多个外键 索引--一个表可以有多个唯一索引

Oracle 主键约束

Oracle 主键约束 主键约束用于惟一地确定表中的每一行数据。在一个表中,最多只能有一个主键约束,主键约束即可以是一个列组成的,也可能是由两个或两个以上列组成的。对于表中的每一行数据,主键约束列都是不同的,主键约束同时也具有非空约束。 如果主键约束由一列组成时,该主键约束被称为行级约束。如果主键约束由两个或两个以列组成时,则该主键约束被称为表级约束。这两种不同类型的主键,在定义上有一点差异。 例如,在定义EMPLOYEES表时,为表定义了一个表级主键约束EMP_PK,该主键约束由EMPNO列组成: SQL> create table employees( 2 empno number(10), 3 ename varchar2(20) not null, 4 sex char(2), 5 salary number(8,2), 6 hiredate date default sysdate, 7 job varchar2(10), 8 email varchar2(50), 9 deptno number(3) not null, 10 constraint EMP_PK primary key (empno,ename)); 表已创建。 使用ALTER TABLE语句增加主键约束的部分语法形式如下: alter table table_name add constraint constraint_name primary key(column1[,column2]); 如果表上已经存在主键约束,那么当试图在该表上再增加一个主键约束时,系统就会生生一个错误信息。即使在不同的列上增加约束也是如此。例如,当在EMPLOYEES表的EMAIL列上再增加一个约束时,系统将产生“表中能具有一个主键”的错误消息。如下所示: SQL> alter table employees 2 add constraint emp_email_pk primary key (email); add constraint emp_email_pk primary key (email) * 第 2 行出现错误: ORA-02260: 表只能具有一个主键 与NOT NULL约束相同,当为表添加主键约束时,如果该表中已经存在数据,并且主键列具有相同的值或存在NULL值,则添加主键约束的操作将失败。 如果要为PRIMARY KEY约束指定名称,则必须使用CONSTRAINT关键字,如上面的示例所示。如果要使用系统自动为其分配的名称,则可以省略CONSTRAINT关键字。例如,下面的语句在创建EMPLOYEES表时在EMPNO列上定义了一个主键约束: create table employees( empno number(10) primary key, …

一个表可以创建多个主键吗

二、判断题 1.一个表可以创建多个主键吗。 2.创建唯一性索引的列可以有一些重复的值。 3.smallint 是SQL的数据类型。 4.SQL Server不允许字段名为汉字。 5.职称 in ('教授', '副教授'')与职称 = '教授' or 职称 = '副教授' 等 价吗? 6.如果规则当前绑定到某列或用户定义的数据类型,不能解除绑定能直接删 除规则? 7.在表中创建一个标识列(IDENTITY),当用户向表中插入新的数据行时,系 统自动为该行标识列赋值吗? 8.创建唯一性索引的列可以有一些重复的值? 9.固定数据库角色:db_datawriter 的成员删除本数据库内任何表中的数据 吗? 10.数据库设计前只需选择数据库分析设计人员。 11.恢复是利用冗余数据来重建数据库。 12.定义外键级级联是为了保证相关表之间数据的一致性吗? 13.存储过程的输出结果可以传递给一个变量。 14.视图具有与表相同的功能,在视图上也可以创建触发器。 15.SQL Server 2000不具有数据的导入与导出功能。 16.数据的完整性主要防范的对象是非法用户。 17.概念结构设计的工具是E—R模型。 18.设计好的数据库管理系统在投入使用后出现问题由使用方负责。 19.缺省情况下,所创建的索引是非聚集索引? 20.触发器是可在程序中被调用执行。 21.sa能否创建和删除数据库角色? 22.因为通过视图可以插入、修改或删除数据,因此视图也是一个实在表, SQL SERVER将它保存在syscommens系统表中。

23.guest用户必须关联一个登录账号才可以在数据库中创建。数据库中的非 guest用户账号都必须关联一个登录账号。 24.可以在企业管理器中修改数据库的名称。 25.恢复数据,可以在查询分析器中使用这样的命令:BACKUP DATABASE database_name FROM backup。 26.DELETE语句只是删除表中的数据,表本身依然存在数据库中。 27.在数据库中建立的索引越多越好。 28.在SQL SERVER中,触发器的执行是在数据的插入、更新或删除之前执行的。 29.通配符“_”表示某单个字符。 30.数据库不允许存在数据冗余。 31.每一个服务器必须属于一个服务器组。一个服务器组可以包含0个、一个或 多个服务器。 32.在SQL Server系统中,数据信息和日志信息不能放在同一个操作系统文件 中。 33.在使用子查询时,必须使用括号把子查询括起来,以便区分外查询和子查 询。 34.存储过程是存储在服务器上的一组预编译的Transcat-SQL语句。 35.创建触发器的时候可以不是表的所有者或数据库的所有者。 36.设置惟一约束的列可以为空吗? 37.一个表可以创建多个主键吗? 38.SQL Server有数据备份功能但没有数据还原功能。 39.数据库是用来存放表和索引的逻辑实体。 40.ODBC是由Microsoft定义的一种数据库访问标准。 41.创建存储过程必须在企业管理器中进行。 42.触发器主要是通过表操作事件进行触发而被执行的。 43.SQL Server 自动为primary key约束的列建立一个索引。 44.SQL Server的数据库可以转换成Access数据库。 45.删除表时,表中的触发器被同时删除。 46.数据库的名称一旦建立就不能重命名。

数据库主键外键设计原则 sky-v 博客园

数据库主键外键设计原则- sky-v - 博客园 主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。 必须将数据库模式从理论上的逻辑设计转换为实际的物理设计。而主键和外键的结构是这个设计过程的症结所在。一旦将所设计的数据库用于了生产环境,就很难对这些键进行修改,所以在开发阶段就设计好主键和外键就是非常必要和值得的。 主键: 关系数据库依赖于主键---它是数据库物理模式的基石。主键在物理层面上只有两个用途: 1. 惟一地标识一行。 2. 作为一个可以被外键有效引用的对象。 基于以上这两个用途,下面给出了我在设计物理层面的主键时所遵循的一些原则: 1. 主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。 2. 主键应该是单列的,以便提高连接和筛选操作的效率。

注:使用复合键的人通常有两个理由为自己开脱, 而这两个理由都是错误的。其一是主键应当具有实际意义,然而,让主键具有意义只不过是给人为地破坏数据库提供了方便。其二是利用这种方法可以在描述多对多关系的连接表中使用两个外部键来作为主键,我也反对这种做法,理由是:复合主键常常导致不良的外键,即当连接表成为另一个从表的主表,而依据上面的第二种方法成为这个表主键的一部分,然,这个表又有可能再成为其它从表的主表,其主键又有可能成了其它从表主键的一部分,如此传递下去,越靠后的从表,其主键将会包含越多的列了。 3. 永远也不要更新主键。实际上,因为主键除了惟一地标识一行之外,再没有其他的用途了,所以也就没有理由去对它更新。如果主键需要更新,则说明主键应对用户无意义的原则被违反了。 注:这项原则对于那些经常需要在数据转换或多数 据库合并时进行数据整理的数据并不适用。 4. 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。 5. 主键应当有计算机自动生成。如果由人来对主键的创建进行干预,就会使它带有除了惟一标识一行以外的意义。一旦越过这个界限,就可能产生认为修改主键的动机,这样,这种系统用来链接记录行、管理记录行的关键手段就

数据库中的五种约束

数据库中的五种约束 数据库中的五种约束及其添加方法 五大约束 1.—-主键约束(Primay Key Coustraint)唯一性,非空性 2.—-唯一约束(Unique Counstraint)唯一性,可以空,但只能有一个 3.—-检查约束(Check Counstraint)对该列数据的范围、格式的限制(如:年龄、性别等) 4.—-默认约束(Default Counstraint)该数据的默认值 5.—-外键约束(Foreign Key Counstraint)需要建立两表间的关系并引用主表的列 五大约束的语法示例 1.—-添加主键约束(将stuNo作为主键) alter table stuInfo add constraint PK_stuNo primary key(stuNo) 2.—-添加唯一约束(身份证号唯一,因为每个人的都不一样) alter table stuInfo add constraint UQ_stuID unique(stuID) 3.—-添加默认约束(如果地址不填默认为“地址不详”) alter table stuInfo add constraint DF_stuAddress default(‘地址不详’)for stuAddress 4.—-添加检查约束(对年龄加以限定15-40岁之间) alter table stuInfo add constraint CK_stuAge check(stuAge between15and40) alter table stuInfo add constraint CK_stuSex check(stuSex=’男’or stuSex=’女′) 5.—-添加外键约束(主表stuInfo和从表stuMarks建立关系,关联字段stuNo) alter table stuInfo add constraint FK_stuNo foreign key(stuNo)references stuinfo(stuNo) 约束(Constraint)是Microsoft SQL Server提供的自动保持数据库完整性的一种方法,定义了可输入表或表的单个列中的数据的限制条件(有关数据完整性的介绍请参见第9章)。在SQL Server中有5种约束:主关键字约束(Primary Key Constraint)、外关键字约束(Foreign Key Constraint)、惟一性约束(Unique Constraint)、检查约束(Check Constraint)和缺省约束(Default Constraint)。 1主关键字约束 主关键字约束指定表的一列或几列的组合的值在表中具有惟一性,即能惟一地指定一行记录。每个表中只能有一列被指定为主关键字,且IMAGE和TEXT类型的列不能被指定为主关键字,也不允许指定主关键字列有NULL属性。

mysql 约束的使用

约束类型 总的来说有五种:唯一性和主键约束、外键约束、检查约束、空值约束、默认值约束,有五大关键词,UNIQUE和Primary Key, Foreign Key, CHECK, NOT NULL, DEFAULT 1。唯一性和主键约束。 要求某一列,或几列不能有重复的值,建立主键约束和唯一约束时,Oralce会基于约束列自动建立唯一索引;主键约束不允许为NULL,唯一约束允许为NULL,一张表只能建立一个主键约束。唯一性和主键约束类似,只是关键词不同而已,语法一致。创建约束 CREATE TABLE TABLE_NAME ( COL1 VARCHAR2(32) NOT NULL PRIMARY KEY, ) CREATE TABLE TABLE_NAME ( COL1 VARCHAR2(32) NOT NULL CONSTRAINT PK_ID PRIMARY KEY, ) CREATE TABLE TABLE_NAME ( COL1 VARCHAR2(32) NOT NULL, COL2 VARCHAR2(32) NOT NULL Foreign Key, CONSTRAINT PK_TABLE_NAME PRIMARY KEY(COL1,COL2) ) 修改约束 ALTER TABLE Table_Name ADD CONSTRAINT PK_Table_Name PRIMARY KEY NONCLUSTERED(Col1)【这里表明了是聚集还是非聚集主键索引】 如果唯一性约束保护多个数据列,那么唯一性约束要作为表约束增加。语法如下:CONSTRAINT CONSTRAINT_NAME (COL1,COL2) UNIQUE USING INDEX TABLESPACE (TABLESPACE_NAME) STORAGE (STORED CLAUSE) 2。外键约束。 剩下的约束写法都是差不多,这里就不多举例了。 CREATE TABLE TABLE_NAME ( COL1 VARCHAR2(32) NOT NULL REFERENCES PRIMARY_TABLE(PRIMARY_COL) ON DELETE CASCADE, ) CREATE TABLE TABLE_NAME ( COL1 VARCHAR2(32) NOT NULL, CONSTRAINT FK_TABLE_NAME FOREIGN KEY REFERENCES PRIMARY_TABLE(PRIMARY_COL) ON DELETE SET NULL

实验6-表的结构设计与约束设计_答案

实验6:SQL Server数据表的结构设计与约束设计1.实验目的 (1)掌握使用SQL Server管理平台和Transact-SQL语句CREATE TABLE和ALTER TABLE创建和修改表的方法。 (2)了解SQL Server的常用数据类型。 (3)掌握SQL Server管理平台和Transact-SQL语句定义和删除约束的方法,并了解约束的类型。 2.实验内容及步骤 (1)启动SQL Server管理平台,创建studentsdb数据库。 Create database studentsdb (2)在studentsdb数据库中包含有数据表student_info、curriculum、grade,这些表的数据结构如图1-1至图1-3所示。 图1-1 学生基本情况表student_info 图1-2 课程信息表curriculum 图1-3 学生成绩表grade USE studentsdb go CREATE TABLE student_info

(学号char(4), 姓名char(8), 性别char(2), 出生日期datetime, 家庭住址varchar(50), 备注text ) GO CREATE TABLE curriculum (课程编号char(4), 课程名称nchar(50), 学分int ) GO CREATE TABLE grade (学号char(4), 课程编号char(4), 分数float ) GO (3)在SQL Server管理平台中创建student_info、curriculum、grade表。将student_info表的学号列设置为主键,非空。将curriculum表的课程编号设置为主键,非空。将grade表主键设置为学号和课程编号。 --1添加非空约束(设置主键约束时字段值不能为空,先设置非空,再设置主键约束) ALTER TABLE student_info ALTER COLUMN学号char(4)NOT NULL ALTER TABLE curriculum ALTER COLUMN课程编号char(4)NOT NULL ALTER TABLE grade ALTER COLUMN学号char(4)NOT NULL ALTER TABLE grade ALTER COLUMN课程编号char(4)NOT NULL --2 添加主键 ALTER TABLE student_info ADD PRIMARY KEY (学号) ALTER TABLE curriculum ADD PRIMARY KEY (课程编号) ALTER TABLE grade ADD PRIMARY KEY (学号,课程编号) (4)在SQL Server管理平台中为student_info、curriculum、grade表添加数据。数据如图1-4至图1-6所示。

相关文档
最新文档