1、第第5 5章章 MySQL MySQL索引与完整性约束索引与完整性约束MySQL索引索引5.15.2MySQL索引索引创建创建MySQL数据完整性约束数据完整性约束5.35.1 MySQL5.1 MySQL索引索引5.1.1 索引及作用索引及作用1.索引索引索引是根据表中一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表。在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应行的位置,从而快速地找到数据。例如,如果用户创建了xs表中学号列的索引,MySQL将在索引中排序学号列,对于索引中的每一项,MySQL在内部为它保存一个数据文件中实际记录所在位置的“指针”。因此,如果要查
2、找学号为“081241”的学生信息,MySQL能在学号列的索引中找到“081241”的值,然后直接转到数据文件中相应的行,准确地返回该行的数据。5.1.1 5.1.1 索引及作用索引及作用2索引作用索引作用在数据库系统中建立索引主要有以下作用:l快速读取数据;l保证数据记录的唯一性;l实现表与表之间的参照完整性;l在使用GROUP BY、ORDER BY子句进行数据检索时,利用索引可减少排序和分组的时间。5.1.1 5.1.1 索引及作用索引及作用3.MySQL索引索引在MySQL 5.6中,所有的MySQL列类型都能被索引,但要注意以下几点:l只有当表类型为MyISAM、InnoDB或BDB
3、时,才可以向有NULL、BLOB或TEXT列中添加索引。l一个表最多可有16个索引。最大索引长度是256个字节。l对于CHAR和VARCHAR列,可以索引列的前缀。这样索引的速度更快并且比索引整个列需要较少的磁盘空间。lMySQL能在多个列上创建索引。索引可以由最多15个列组成(在CHAR和VARCHAR列上,也可以使用列的前缀作为索引的部分)。5.1.2 5.1.2 索引的分类索引的分类1.BTREE索引索引目前大部分MySQL索引都是以B-树(BTREE)方式存储的,索引类型分成下列几个。(1)普通索引()普通索引(INDEX)这是最基本的索引类型,它没有唯一性之类的限制。创建普通索引的关
4、键字是INDEX。(2)唯一性索引()唯一性索引(UNIQUE)这种索引和前面的普通索引基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须是唯一的。创建唯一性索引的关键字是UNIQUE。(3)主键()主键(PRIMARY KEY)主键是一种唯一性索引,它必须指定为“PRIMARY KEY”。主键一般在创建表的时候指定,也可以通过修改表的方式加入主键。但是每个表只能有一个主键。(4)全文索引()全文索引(FULLTEXT)MySQL支持全文检索和全文索引。在MySQL中,全文索引的索引类型为FULLTEXT。5.1.2 5.1.2 索引的分类索引的分类2哈希索引(哈希索引(HASH)当
5、表类型为MEMORY或HEAP时,除了BTREE索引,MySQL还支持哈希索引(HASH)。使用哈希索引,不需要建立树结构,但是所有的值都保存在一个列表中,这个列表指向相关页和行。当根据一个值获取一个特定的行时,哈希索引非常快。5.2 MySQL5.2 MySQL索引索引创建创建1CREATE INDEX语句创建语句创建使用CREATE INDEX语句可以在一个已有表上创建索引,一个表可以创建多个索引。语法格式:语法格式:CREATE UNIQUE|FULLTEXT|SPATIAL INDEX 索引名 索引类型 ON 表名(索引列名.)索引选项.索引列名=:列名(长度)ASC|DESC说明:说
6、明:lUNIQUE|FULLTEXT|SPATIAL:UNIQUE表示创建的是唯一性索引;FULLTEXT表示创建全文索引;SPATIAL表示为空间索引,可以用来索引几何数据类型的列(本书不讨论这种索引)。l索引名:索引在一个表中名称必须是唯一的。l索引类型:MySQL支持的索引类型有BTREE和HASH。l索引列名:创建索引的列名后的长度表示该列前面创建索引字符个数。这可使索引文件大大减小,从而节省磁盘空间。5.2 MySQL5.2 MySQL索引索引创建创建【例5.1】根据xs表的学号列上的前5个字符建立一个升序索引xh-_xs。use xscjcreate index xh_xs on
7、xs(学号(5)asc);也可以在一个索引的定义中包含多个列,中间用逗号隔开,但它们属于同一个表,这样的索引叫作复合索引。【例5.2】在xs_kc表的学号列和课程号列上建立一个复合索引xskc-_in。create index xskc_in on xs_kc(学号,课程号);5.2 MySQL5.2 MySQL索引索引创建创建2ALTER TABLE语句创建语句创建前面章节介绍了如何使用ALTER TABLE语句修改表,其中也包括向表中添加索引。语法格式如下:语法格式如下:ALTER IGNORE TABLE 表名.|ADD INDEX|KEY 索引名 /*添加索引*/索引类型(索引列名.)
8、索引选项.|ADD CONSTRAINT symbol PRIMARY KEY/*添加主键*/索引类型(索引列名.)索引选项.|ADD CONSTRAINT symbolUNIQUE INDEX|KEY 索引名索引类型(索引列名.)索引选项./*添加唯一性索引*/|ADD FULLTEXT INDEX|KEY 索引名(索引列名.)索引选项./*添加全文索引*/|ADD SPATIAL INDEX|KEY 索引名(索引列名.)索引选项./*添加空间索引*/|ADD CONSTRAINT symbol FOREIGN KEY 索引名(索引列名.)参照性定义 /*添加外键*/|DISABLE KEY
9、S|ENABLE KEYS5.2 MySQL5.2 MySQL索引索引创建创建【例5.3】在xs表的姓名列上创建一个非唯一的索引。alter table xsadd index xs_xm using btree(姓名);【例5.4】以xs表为例(假设表中主键未定),创建这样的索引,以加速表的检索速度:alter table xsadd index mark(出生日期,性别);这个例子创建了一个复合索引。5.2 MySQL5.2 MySQL索引索引创建创建如果想要查看表中创建的索引的情况,可以使用SHOW INDEX FROM 表名语句,例如:show index from xs;系统显示已创
10、建的索引信息如下:5.2 MySQL5.2 MySQL索引索引创建创建3在建立表时创建索引在建立表时创建索引在前两种情况下,索引都是在表建立之后创建的。索引也可以在创建表时一起创建。在创建表的CREATE TABLE语句中可以包含索引的定义。语法格式:语法格式:CREATE TEMPORARY TABLE IF NOT EXISTS 表名 (列定义 ,.|索引定义)表选项 select语句;索引定义索引定义=:CONSTRAINT symbolPRIMARY KEY 索引类型(索引列名.)/*主键*/|INDEX|KEY 索引名 索引类型(索引列名.)/*索引*/|CONSTRAINT sym
11、bol UNIQUE INDEX|KEY 索引名 索引类型(索引列名.)/*唯一性索引*/|FULLTEXT|SPATIAL INDEX|KEY 索引名(索引列名.)/*全文索引*/|CONSTRAINT symbol FOREIGN KEY 索引名(索引列名.)参照性定义 /*外键*/5.2 MySQL5.2 MySQL索引索引创建创建【例5.5】在mytest数据库中创建成绩(cj)表,学号和课程号的联合主键,并在成绩列上创建索引。use mytestcreate table xs_kc(学号 char(6)not null,课程号 char(3)not null,成绩 tinyint(1
12、),学分 tinyint(1),primary key(学号,课程号),index cj(成绩);5.2 MySQL5.2 MySQL索引索引创建创建4删除索引删除索引当一个索引不再需要的时候,可以用DROP INDEX语句或ALTER TABLE语句删除它。(1)使用)使用DROP INDEX删除删除语法格式:语法格式:DROP INDEX 索引名 ON 表名(2)使用)使用ALTER TABLE删除删除语法格式:语法格式:ALTER IGNORE TABLE 表名.|DROP PRIMARY KEY/*删除主键*/|DROP INDEX|KEY 索引名/*删除索引*/|DROP FOREI
13、GN KEY fk_symbol/*删除外键*/5.2 MySQL5.2 MySQL索引索引创建创建【例5.6】删除xs表上的mark索引。alter table xsdrop index mark;读者可使用SHOW INDEX FROM 表名语句查看执行结果。5.3 MySQL5.3 MySQL数据完整性约束数据完整性约束5.3.1 主键约束主键约束可以用两种方式定义主键,作为列或表的完整性约束。作为列的完整性约束时,只需在列定义的时候加上关键字PRIMARY KEY,这个在3.2.1节中已作过介绍。作为表的完整性约束时,需要在语句最后加上一条PRIMARY KEY(col_name,)语
14、句。【例5.7】创建表xs1,将姓名定义为主键。create table xs1(学号 varchar(6)null,姓名 varchar(8)not null primary key,出生日期 datetime);5.3.1 5.3.1 主键约束主键约束当表中的主键为复合主键时,只能定义为表的完整性约束。【例5.8】创建course表来记录每门课程的学生学号、姓名、课程号、学分和毕业日期。其中学号、课程号和毕业日期构成复合主键。create table course(学号 varchar(6)not null,姓名 varchar(8)not null,毕业日期date not null,课
15、程号varchar(3),学分tinyint,primary key(学号,课程号,毕业日期);5.3.1 5.3.1 主键约束主键约束原则上,任何列或者列的组合都可以充当一个主键。但是主键列必须遵守一些规则。这些规则源自于关系模型理论和MySQL所制定的以下规则:(1)每个表只能定义一个主键。来自关系模型的这一规则也适用于MySQL。(2)关系模型理论要求必须为每个表定义一个主键。然而,MySQL并不要求这样,可以创建一个没有主键的表。(3)表中的两个不同的行在主键上不能具有相同的值,即所谓的“唯一性规则”。(4)如果从一个复合主键中删除一列后,剩下的列构成的主键仍然满足唯一性原则,那么,这
16、个复合主键是不正确的,这条规则称为“最小化规则”(Minimality Rule)。也就是说,复合主键不应包含任何不必要的列。(5)一个列名在一个主键的列的列表中只能出现一次。5.3.1 5.3.1 主键约束主键约束MySQL自动地为主键创建一个索引。通常,这个索引名为PRIMARY。然而,可以重新给这个索引取名。【例5.9】创建【例5.9】中的course表,把主键创建的索引命名为index_course。create table course(学号varchar(6)not null,姓名varchar(8)not null,毕业日期date not null,课程号varchar(3),
17、学分tinyint,primary key index_course(学号,课程号,毕业日期);5.3.2 5.3.2 替代键约束替代键约束在关系模型中,替代键像主键一样,是表的一列或一组列,它们的值在任何时候都是唯一的。替代键是没有被选作主键的候选键。定义替代键的关键字是UNIQUE。【例5.10】在表xs1中将姓名列定义为一个替代键。create table xs1(学号 varchar(6)null,姓名 varchar(8)not null unique,出生日期 datetime null,primary key(学号);5.3.2 5.3.2 替代键约束替代键约束替代键还可以定义为
18、表的完整性约束,故前面语句也可这样定义:create table xs1(学号 varchar(6)null,姓名 varchar(8)not null,出生日期 datetime null,primary key(学号),unique(姓名);5.3.2 5.3.2 替代键约束替代键约束在MySQL中,替代键和主键的区别主要有以下几点:(1)一个数据表只能创建一个主键。但一个表可以有若干个UNIQUE键,并且它们甚至可以重合,例如,在C1和C2列上定义了一个替代键,并且在C2和C3上定义了另一个替代键,这两个替代键在C2列上重合了,而MySQL允许这样。(2)主键字段的值不允许为NULL,而
19、UNIQUE字段的值可取NULL,但是必须使用NULL或NOT NULL声明。(3)一般创建PRIMARY KEY约束时,系统会自动产生PRIMARY KEY索引。创建UNIQUE约束时,系统自动产生UNIQUE索引。5.3.3 5.3.3 参照完整性约束参照完整性约束定义外键的语法格式已经在介绍索引时给出了,这里列出“参照性定义”。语法格式:语法格式:参照性定义=:REFERENCES 表名(索引列名.)ON DELETE RESTRICT|CASCADE|SET NULL|NO ACTION ON UPDATE RESTRICT|CASCADE|SET NULL|NO ACTION索引列名
20、=:列名(长度)ASC|DESC5.3.3 5.3.3 参照完整性约束参照完整性约束参照动作包含两部分:在第一部分中,指定这个参照动作应用哪一条语句。这里有两条相关的语句,即UPDATE和DELETE语句;在第二部分中,指定采取哪个动作。可能采取的动作是RESTRICT、CASCADE、SET NULL、NO ACTION和SET DEFAULT。5.3.3 5.3.3 参照完整性约束参照完整性约束接下来说明这些不同动作的含义。lRESTRICT:当要删除或更新父表中被参照列上在外键中出现的值时,拒绝对父表的删除或更新操作。lCASCADE:从父表删除或更新行时自动删除或更新子表中匹配的行。l
21、SET NULL:当从父表删除或更新行时,设置子表中与之对应的外键列为NULL。如果外键列没有指定NOT NULL限定词,这就是合法的。lNO ACTION:NO ACTION意味着不采取动作,就是如果有一个相关的外键值在被参考的表里,删除或更新父表中主要键值的企图不被允许,和RESTRICT一样。lSET DEFAULT:作用和SET NULL一样,只不过SET DEFAULT是指定子表中的外键列为默认值。5.3.3 5.3.3 参照完整性约束参照完整性约束外键目前只可以用在那些使用InnoDB存储引擎创建的表中,对于其他类型的表,MySQL服务器能够解析CREATE TABLE语句中的FO
22、REIGN KEY语法,但不能使用或保存它。【例5.11】创建xs1表,所有的xs表中学生学号都必须出现在xs1表中,假设已经使用学号列作为主键创建了xs表。create table xs1(学号 varchar(6)null,姓名 varchar(8)not null,出生日期 datetime null,primary key(姓名),foreign key(学号)references xs(学号)on delete restrict on update restrict);5.3.3 5.3.3 参照完整性约束参照完整性约束这意味着,对于xs1表中的每一个学号,都执行一次检查,看这个号码
23、是否已经出现在xs表的学号列(主键)中。如果情况不是这样,用户或应用程序会接收到一条出错消息,并且更新被拒绝。这也适用于使用UPDATE语句更新xs1表中的学号列。即MySQL确保了xs1表中的学号列的内容总是xs表中学号列的内容的一个子集。也就是说,下面的SELECT语句不会返回任何行:select*from xs1 where 学号 not in (select 学号 from xs );5.3.3 5.3.3 参照完整性约束参照完整性约束当指定一个外键的时候,以下的规则适用:(1)被参照表必须已经用一条CREATE TABLE语句创建了,或者必须是当前正在创建的表。在后一种情况下,参照表
24、是同一个表。(2)必须为被参照表定义主键。(3)必须在被参照表的表名后面指定列名(或列名的组合)。这个列(或列组合)必须是这个表的主键或替代键。(4)尽管主键是不能够包含空值的,但允许在外键中出现一个空值。这意味着,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。(5)外键中的列的数目必须和被参照表的主键中的列的数目相同。(6)外键中的列的数据类型必须和被参照表的主键中的列的数据类型对应相等。5.3.3 5.3.3 参照完整性约束参照完整性约束与外键相关的被参照表和参照表可以是同一个表。这样的表称为自参照表(Self-referencing Table),这种结构称为自参照完
25、整性(Self-referential Integrity)。例如,可以创建这样的xs2表:create table xs2(学号 varchar(6)not null,姓名 varchar(8)not null,出生日期 datetime null,primary key(学号),foreign key(学号)references xs1(学号);5.3.3 5.3.3 参照完整性约束参照完整性约束【例5.12】创建带有参照动作ASCADE的xs1表。create table xs1(学号 varchar(6)not null,姓名 varchar(8)not null,出生日期 datet
26、ime null,primary key(学号),foreign key(学号)references xs(学号)on update cascade);5.3.4 CHECK5.3.4 CHECK完整性约束完整性约束CHECK完整性约束在创建表的时候定义。可以定义为列完整性约束,也可定义为表完整性约束。语法格式:语法格式:CHECK(expr)【例5.13】创建表student,只包括学号和性别两列,性别只能是男或女。create table student(学号 char(6)not null,性别 char(1)not null check(性别 in(男,女);5.3.4 CHECK5.
27、3.4 CHECK完整性约束完整性约束【例5.14】创建表student1,只包括学号和出生日期两列,出生日期必须大于1990年1月1日。create table student1(学号 char(6)not null,出生日期 date not null check(出生日期1990-01-01);5.3.4 CHECK5.3.4 CHECK完整性约束完整性约束前面的CHECK完整性约束中使用的表达式都很简单,MySQL还允许使用更为复杂的表达式。例如,可以在条件中加入子查询,下面举个例子。【例5.15】创建表student2,只包括学号和性别两列,并且确认性别列中的所有值都来源于stude
28、nt表的性别列中。create table student2(学号 char(6)not null,性别 char(1)not null check(性别 in (select 性别 from student);5.3.4 CHECK5.3.4 CHECK完整性约束完整性约束如果指定的完整性约束中,要相互比较一个表的两个或多个列,那么该列完整性约束必须定义表完整性约束。【例5.16】创建表student3,有学号、最好成绩和平均成绩3列,要求最好成绩必须大于平均成绩。create table student3(学号 char(6)not null,最好成绩 int(1)not null,平均成
29、绩 int(1)not null,check(最好成绩平均成绩);5.3.5 5.3.5 命名完整性约束命名完整性约束CONSTRAINT关键字用来指定完整性约束的名字,语法格式为:CONSTRAINT symbolsymbol为指定的名字,这个名字在完整性约束的前面被定义,在数据库里这个名字必须是唯一的。如果它没有被给出,则MySQL自动创建这个名字。只能给表完整性约束指定名字,而无法给列完整性约束指定名字。【例5.17】创建与【例5.8】中相同的xs1表,并为主键命名。create table xs1(学号 varchar(6)null,姓名 varchar(8)not null,出生日期 datetime null,constraint primary_key_xs1primary key(姓名);5.3.6 5.3.6 删除完整性约束删除完整性约束如果使用一条DROP TABLE语句删除一个表,所有的完整性约束就都自动被删除了。被参照表的所有外键也都被删除了,使用ALTER TABLE语句,完整性可以独立地被删除,而不必删除表本身。删除完整性约束的语法和删除索引的语法一样。【例5.18】删除创建的表xs1的主键。alter table xs1 drop primary key;删除前后的效果如下: