Ch7. Database Manage(数据库管理)
1. Integrity Constraints (完整性约束)
- 数据完整性:存储在数据库中的所有数据值均正确的状态。它是应防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。
1)实体完整性
实体完整性是对关系中记录的唯一性,也就是主键的约束。准确地说,实体完整性是指关系中的主属性值不能为Null且不能有相同值。定义表中的所有行唯一的标识,一般用主键,唯一索引unique关键字及identity属性;比如说我们的身份证号码,可以唯一标识一个人。
将Student表中的Sno属性定义为码。
1
2
3
4
5
6
7CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY, /*在列级定义主码*/
Sname CHAR(20) NOT NULL,
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20)
);或者
1
2
3
4
5
6
7
8CREATE TABLE Student
(Sno CHAR(9),
Sname CHAR(20) NOT NULL,
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20),
PRIMARY KEY(Sno) /*在表级定义主码*/
);
将SC表中的Sno,Cno属性组定义为码。
1
2
3
4
5
6CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT,
PRIMARY KEY(Sno,Cno) /*只能在表级定义主码*/
);
实体完整性检查和违约处理
用PRIMARY KEY短语定义了关系的主码后,每当用户程序对基本表插入一条记录或者对主码列进行更新操作时,DBMS将按实体完整性规则自动进行检查。包括:
1.检查主码值是否唯一,如果不唯一则拒绝插入或修改。
2.检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。从而保证了实体完整性。
2)参照完整性
参照完整性是对关系数据库中建立关联关系的数据表间数据参照引用的约束,也就是对外键的约束。准确地说,参照完整性是指关系中的外键必须是另一个关系的主键有效值,或者是NULL。参考完整性维护表间数据的有效性,完整性,通常通过建立外部键联系另一表的主键实现,还可以用触发器来维护参照完整性。
关系SC中一个元组表示一个学生选修的某门课程的成绩,(Sno,Cno)是主码。Sno,Cno分别参照引用Student表的主码和Course表的主码。定义SC中参照完整性。
1
2
3
4
5
6
7
8CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT ,
PRIMARY KEY (Sno,Cno), /*在表级定义实体完整性*/
FOREIGN KEY(Sno) REFERENCES Student(Sno), /*在表级定义参照完整性*/
FOREIGN KEY(Cno) REFERENCES Course(Cno) /*在表级定义参照完整性*/
);
参照完整性检查和违约处理
一个参照完整性将两个表中的相应元组联系起来了。因此,对被参照表和参照表进行增删改操作时有可能破坏参照完整性,必须进行检查。
例如,对表SC和Student有四种可能破坏参照完整性的情况,如下表:
1.SC表中增加一个元组,该元组的Sno属性的值在表Student中找不到一个元组,其Sno属性的值与之相等。
2.修改SC表中的一个元组,修改后该元组的Sno属性的值在表Student中找不到一个元组,其Sno属性的值与之相等。
3.从Student表删除一个元组,造成SC表中某些元组的Sno属性的值在表Student中找不到一个元组,其Sno属性的值与之相等。4.修改Student表中一个元组的Sno属性,造成SC表中某些元组的Sno属性的值在表Student中找不到一个元组,其Sno属性的值与之相等。
上述的不一致发生时,系统可以采用以下的策略加以处理。
- 1.拒绝(NO ACTION)执行
- 不允许该操作执行。该策略一般设置为默认策略。
- 2.级连(CASCADE)操作
- 当删除或修改被参照表(Student)的一个元组造成了与参照表(SC)的不一致,则删除或修改参照表中的所有造成不一致的元组。
例如,删除Student表中的元组,Sno值为14042401,则从要SC表中级连删除SC.Sno=‘14042401’的所元组。
- 当删除或修改被参照表(Student)的一个元组造成了与参照表(SC)的不一致,则删除或修改参照表中的所有造成不一致的元组。
3.设置为空值
当删除或修改被参照表的一个元组时造成了不一致,则将参照表中的所有造成不一致的元组的对应属性设置为空值。
示例:
例如,有下面2个关系
学生(学号,姓名,性别,专业号,年龄)
专业(专业号,专业名)
学生关系的“专业号”是外码,因为专业号是专业关系的主码。假设专业表中某个元组被删除,专业号为12,按照设置为空值的策略,就要把学生表中专业号=12的所有元组的专业号设置为空值。这对应了这样的语义:某个专业删除了,该专业的所有学生专业未定,等待重新分配专业。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT,
/*在表级定义实体完整性*/
PRIMARY KEY(Sno,Cno),
/*在表级定义参照完整性*/
FOREIGN KEY(Sno) REFERENCES Student(Sno)
/*当删除student表中的元组时,级连删除SC表中相应的元组*/
ON DELETE CASCADE
/*当更新student表中的Sno时,级连更新SC表中相应的元组*/
ON UPDATE CASCADE,
/*在表级定义参照完整性*/
FOREIGN KEY(Cno) REFERENCES Course(Cno)
/*当删除course表中的元组造成了与SC表不一致时拒绝删除*/
ON DELETE NO ACTION
/*当更新course表中的cno时,级连更新SC表中相应的元组*/
ON UPDATE CASCADE,
);
- 1.拒绝(NO ACTION)执行
示例:
std3表结构:
1
2
3
4
5
6
7
8create table std3 (
id number(6) ,
name varchar(200) constraint std3_name_nn not null,
score number(10,2) ,
email varchar(20) , -- 表级约束
constraint std3_email_uk unique(email) ,
constraint std3_id_pk primary key(id)
)std3中数据如下:
std5表结构(外键级联删除):
1
2
3
4
5
6
7
8
9
10create table std5 (
id number(6) ,
name varchar(200) constraint std4_name_nn not null,
score number(10,2) ,
email varchar(20) ,
friend_id number(6) , -- 表级约束
constraint std5_email_uk unique(email) ,
constraint std5_id_pk primary key(id) ,
constraint std5_friend_id_fk foreign key(friend_id) references std3(id) on delete cascade
)std5中数据如下:
std6表结构(外键级联删除制空):
1
2
3
4
5
6
7
8
9
10create table std6 (
id number(6) ,
name varchar(200) constraint std6_name_nn not null,
score number(10,2) ,
email varchar(20) ,
friend_id number(6) , -- 表级约束
constraint std6_email_uk unique(email) ,
constraint std6_id_pk primary key(id) ,
constraint std6_friend_id_fk foreign key(friend_id) references std3(id) on delete set null
)std6中数据如下:
级联操作:
此时删除std3中‘300001’号数据以后:
std5表:
std6表:
注:级联删除会删除相关联子表中的数据,而级联制空会将子表中相关联的数据置空而不会删除
3)用户定义的完整性
1.属性上的约束条件的定义
在CREATE TABLE 中定义属性的同时可以根据应用要求,定义属性上的约束条件,即属性值限制,包括:
- 列值非空(NOT NULL短语)
- 列值唯一(UNIQUE短语)
- 检查列值是否满足一个布尔表达式(CHECK语句)
不允许取空值
在定义SC表时,说明Sno、Cno、Grade属性不允许取空值。
1
2
3
4
5
6
7
8CREATE TABLE SC
(Sno CHAR(9) NOT NULL. /*Sno属性不允许取空值*/
Cno CHAR(4) NOT NULL, /*Cno属性不允许取空值*/
Grade SMALLINT NOT NULL, /*Grade属性不允许取空值*/
/*如果在表级定义实体完整性,隐含了Sno,Cno不允许取空值则在列级不允许取空值的定义就不必写了*/
PRIMARY KEY(Sno,Cno),
…… /*其它语句省略*/
);
列值唯一
建立部门表DEPT,要求部门名称Dname列取值唯一,部门编号Deptno列为主码。
1
2
3
4
5
6CREATE TABLE DEPT
(Deptno NUMERIC(2),
Dname CHAR(9) UNIQUE, /*要求Dname列值唯一*/
Location CHAR(10),
PRIMARY KEY(Deptno)
);
用CHECK短语自定列值应该满足的条件
Student 表的Ssex只允许取“男”或“女”。
1
2
3
4
5
6
7CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY, /*在列级定义主码*/
Sname CHAR(8) NOT NULL, /*Sname属性不允许取空值*/
Ssex CHAR(2) CHECK(Ssex IN ('男','女')), /*性别属性Ssex只允许取’男‘或’女‘*/
Sage SMALLINT,
Sdept CHAR(20)
);SC表的Grade的值应该在0至100之间。
1
2
3
4
5
6
7
8CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT CHECK(Grade>=0 AND Grade<=100),
PRIMARY KEY (Sno,Cno),
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(Cno) REFERENCES Course(Cno)
);
元组上的约束条件的定义:
与属性上约束条件的定义类似,在CREATE TABLE语句中可以用CHECK短语定义元组上的约束条件,即元组级的限制。同属性值限制相比,元组级的限制可以设置不同属性之间的取值的相互约束条件。
当学生的性别是男时,其名字不能以Ms.打头。
1
2
3
4
5
6
7
8
9
10CREATE TABLE Student
(Sno CHAR(9),
Sname CHAR(8) NOT NULL,
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20),
PRIMARY KEY(Sno),
/*定义了元组中Sname和Ssex两个属性值之间的约束条件*/
CHECK(Ssex='女' OR Sname NOT LIKE 'Ms.%')
);
4)完整性约束命名子句
- 定义:以上讲解的完整性约束约束条件都在CHECK TABLE 语句中定义。SQL还在CHECK TABLE 语句中提供了完整性约束命名子句CONSTRAINT,用来对完整性约束条件命名。从而可以灵活地增加、删除一个完整性约束条件。
完整性约束条件命名子句:
1
CONSTRAINT <完整性约束条件名>[PRIMARY KEY 短语|FOREIGN KEY 短语|CHECK 短语]
建立学生登记表Student,要求学号在90000-99999之间,姓名不能取空值,年龄小于30,性别只能是’男‘或’女‘。
1
2
3
4
5
6
7
8
9
10
11CREATE TABLE Student
(Sno NUMERIC(6),
CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999),
Sname CHAR(20),
CONSTRAINT C2 CHECK(Sname NOT NULL),
Sage NUMERIC(3),
CONSTRAINT C3 CHECK(Sage<30),
Ssex CHAR(2),
CONSTRAINT C4 CHECK(Ssex IN('男' ,'女')),
CONSTRAINT StudentKey PRIMARY KEY(Sno)
);建立教师表TEACHER,要求每个教师的应发工资不低于3000元;应发工资实际上就是实发工资列Sal与扣除项Deduct之和。
1
2
3
4
5
6
7
8
9
10CREATE TABLE TEACHER
(Eno NUMERIC(4) PRIMARY KEY,
Ename CHAR(10),
Job CHAR(8),
Sal NUMERIC(7,2),
Deduct NUMERIC(7,2),
Deptno NUMERIC(2),
CONSTRAINT EMPFKey FOREIGN KEY(Deptno) REFERENCES DEPT(Deptno),
CONSTRAINT C1 CHECK (Sal+Deduct >= 3000)
);
修改表中完整性限制:
可以使用ALTER TABLE语句修改表中的完整性限制;去掉Student表中对性别的限制。
1
2ALTER TABLE Student
DROP CONSTRAINT C4;修改表Student中的约束条件,要求学号改为900000-999999之间,年龄由小于30改为小于40.(可以先删除原来的约束条件,再增加新的约束条件)
1
2
3
4
5
6
7
8ALTER TABLE Student
DROP CONSTRAINT C1;
ALTER TABLE Student
ADD CONSTRAINT C1 CHECK (Sno BETWEEN 900000 AND 999999),
ALTER TABLE Student
DROP CONSTRAINT C3;
ALTER TABLE Student
ADD CONSTRAINT C3 CHECK(Sage<40);
5)触发器
定义:trigger,是指事先为某张表绑定一段代码,当表中的某些内容发生改变(增、删、改)的时候,系统会自动触发代码并执行。
触发器包含三个要素,分别为:
事件类型:增删改,即insert、delete和update;
触发时间:事件类型前和后,即before和after;
触发对象:表中的每一条记录(行),即整张表。
每张表只能拥有一种触发时间的一种事件类型的触发器,即每张表最多可以拥有 6 种触发器。
创建触发器:
1
2
3
4
5
6
7
8-- 创建触发器基本语法
delimiter $ -- 自定义符号;临时修改语句结束符,在后续语句中只有遇到自定义符号才会结束语句
create trigger + 触发器名称 + 触发器时间 + 事件类型 on 表名 for each row
begin -- 代表触发器内容开始
-- 触发器内容主体,每行用分号结尾
end -- 代表触发器内容结束
$ -- 自定义符号;用于结束语句
delimiter ; -- 恢复语句结束符trigger_name : 触发器名称,用户自行指定
trigger_time: 触发时机,取值BEFORE(之前)、AFTER(之后)
trigger_event : 出发事件,INSERT、UPDATE、DELETE。(插入、更新、删除)
tbl_name : 需要建立触发器的表名。
trigger_stmt : 触发程序体,可以是一条SQL语句或是BEGIN和END包含的索条语句BEGIN…END详解:
1
2
3BEGIN
[statement_list]
ENDstatement_list 使用方法:
statement_list 代表一个或多个语句的列表,列表内的每条语句都必须用分号(;)来结尾(默认值)
我们可以使用DELIMITERE指定自定义的定界符。
DELIMITER new_delemiter:
new_delemiter 可以设为1个或多个长度的符号,默认的是分号(;),我们可以把它修改为其他符号,如:DELIMITER $(注意:我们修改了定界符使用完了,记得修改回来DELIMITER ;)1
2
3
4
5
6
7
8
9DELIMITER $
create trigger tri_stuInsert after insert
on student for each row
begin
declare c int;
set c = (select stucount from class where classID = new.classID);
update class set stucount = c+1 where classID = new.classID;
end $
DELIMITER;
NEW与OLD关键字:
该关键字,表示触发了触发器的那一行数据。
INSERT触发器中,NEW用来表示将要(BEFORE)或已经(AFTER)插入的新数据。
UPDATE触发器中,OLD用来表示将要或已经被修改的原数据,NEW用来表示将要或已经修改为的新数据。
DELETE触发器中,OLD用来表示将要或已经被删除的原数据。使用方法:
NEW.columnName(columnName为相应数据表某一列名)
另外,OLD是只读的,而NEW则可以在触发器中使用SET赋值,这样不会再次触发触发器,造成循环调用(如每插入一个学生前,都在其学号前加"2013")。
具体示例:
1. 当在删除test表的数据时,会在对应的member对应的id中添加name字段值为world。
1
2
3
4
5
6CREATE TRIGGER test_tt AFTER DELETE ON `test` FOR EACH ROW
BEGIN
DECLARE s VARCHAR(20) DEFAULT 'hello';
SET s = 'world';
UPDATE `member` SET `name` = s WHERE id = OLD.id;
END2. 在删除test表中的一行数据时,能够把删除之前的name数据写入member表中去。
1
2
3
4CREATE TRIGGER test_tt AFTER DELETE ON `test` FOR EACH ROW
BEGIN
UPDATE `member` SET `name` = old.name WHERE id = OLD.id;
END
判断值后调用触发器:
当插入时间小时为20时,对数据进行插入
1
2
3
4
5
6
7
8
9DROP TRIGGER IF EXISTS `ins_info`;
create trigger ins_info
after insert on nhfxelect for each row
begin
if HOUR(new.RecordTime)='20' then
insert into nhfxbyhour (UnitDepName, UnitDepCode, ElectCost, TimeJG, RecordTime)
values( '数统学院', '1', new.USERKWH, '20', new.RecordTime);
end if;
end;再如更新触发器,如果设置的值为某个范围,才进行操作或性别为"男"或"女"才进行操作。
基本语法:
if 判断条件 then
sql语句;
end if;
2. Create Views(创建视图)
1)视图功能
- 视图(子查询):是从一个或多个表导出的虚拟的表,其内容由查询定义。具有普通表的结构,但是不实现数据存储。
- 对视图的修改:单表视图一般用于查询和修改,会改变基本表的数据,多表视图一般用于查询,不会改变基本表的数据。
优点:
简化了操作,把经常使用的数据定义为视图。
我们在使用查询时,在很多时候我们要使用聚合函数,同时还要 显示其它字段的信息,可能还会需要关联到其它表,这时写的语句可能会很长,或如果这个动作频繁发生的话,我们可以创建视图,这以后,我们只需要select * from view就可以啦,这样很方便。
安全性,用户只能查询和修改能看到的数据。
因为视图是虚拟的,物理上是不存在的,只是存储了数据的集合,我们可以将基表中重要的字段信息,可以不通过视图给用户,视图是动态的数据的集合,数据是随着基表的更新而更新。同时,用户对视图不可以随意的更改和删除,可以保证数据的安全性。
逻辑上的独立性,屏蔽了真实表的结构带来的影响。
视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。
缺点:
性能差
数据库必须把视图查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也要把它变成一个复杂的结合体,需要花费一定的时间。
修改限制
当用户试图修改视图的某些信息时,数据库必须把它转化为对基本表的某些信息的修改,对于简单的视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的。
2)创建视图
创建(或修改)视图:
1
2
3
4CREATE VIEW 视图名(列1,列2...)
AS SELECT (列1,列2...)
FROM ...
[With Check Option];1
2CREATE OR REPLACE VIEW 视图名
AS SELECT [...] FROM [...];1
2
3
4
5CREATE VIEW Student(Sno,Sname,Ssex,Sage,Sdept)
AS
SELECT SX.Sno,SX.Sname,SY.Ssex,SX.Sage,SY.Sdept
FROM SX,SY
WHERE SX.Sno=SY.Sno;1
2-- 查看10号部门所有的员工信息,选择所有列则无需在view名后添加列名
Create or replace view v_emp as select * from emp where deptno=10;- 参数:[with check option]可选项,防止用户对数据插入、删除、更新时操作了视图范围外的基本表的数据。
组成视图的属性列名或者全部省略或者全部指定,没有第三种选择。如果省略了视图的各个属性列名,则隐含该视图由子查询中SELECT子句目标列中的诸字段组成。但在下列三种情况下必须明确指定组成视图的所有列名:
(1)某个目标列不是单纯的属性名,而是聚集函数或列表达式;
(2)多表连接时选出了几个同名列作为视图的字段;
(3)需要在视图中为某个列启用新的更合适的名字。
示例:
1. 建立信息系选修了1号课程的学生的视图(包括学号、姓名、成绩)。
1
2
3
4
5
6
7CREATE VIEW IS_SI(Sno, Sname, Grade)
AS
SELECT Student.Sno, Sname,Grade
FROM Student, SC
WHERE Sdept='IS'AND
Student.Sno=SC.Sno AND
SC.Cno= 1;注意:
由于视图IS_S1的属性列中包含了Student表与SC表的同名列Sno,所以必须在视图名后面明确说明视图的各个属性列名。
2. 定义一个反映学生出生年份的视图。
1
2
3CREATE VIEW BT_S(Sno,Sname,Sbirth)
AS SELECT Sno,Sname,2014-Sage
FROM Student;注意:
这里视图BTS是一个带表达式的视图。视图中的出生年份值是通过计算得到的。
3. 将学生的学号及平均成绩定义为一个视图。
1
2
3
4
5CREATE VIEW S_G(Sno, Gavg)
AS
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno;注意:
由于AS子句中SELECT语句的目标列平均成绩是通过作用聚集函数得到的,所以CREATE VIEW中必须明确定义组成S_G视图的各个属性列名。SG是一个分组视图。
视图运用(查询):
1. 使用视图和使用表完全一样,只需要把视图当成一张表就OK了;视图是一张虚拟表。
1
2-- 从视图中检索数据
select * from v_student;2. 从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解(view resolution)。
1
2
3
4
5
6
7
8
9-- 消解过程:
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
-- 相当于
SELECT Sno,Sage
FROM Student
WHERE Sdept='IS' AND Sage<20;3. 在一般情况下,视图查询的转换是直截了当的。但有些情况下,这种转换不能直接进行,查询时就会出现问题。
在SG视图中查询平均成绩在90分以上的学生
学号和平均成绩,语句为1
2
3SELECT*
FROM S_G
WHERE Gavg>=90;定义SG视图的子查询为
1
2
3SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;将本例中的查询语句与定义SG视图的子查询结合,形成下列查询语句:
1
2
3
4SELECT Sno,AVG(Grade)
FROM SC
WHERE AVG(Grade)>=90
GROUP BY Sno;注意:
因为WHERE子句中是不能用聚集函数作为条件表达式的,因此执行此修正后的查询将会出现语法错误。正确转换的查询语句应该是:
1
2
3
4SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>=90;
3)修改视图
视图与数据变更:
1
INSERT INTO v_order(pid,pname,price) VALUES('p010','柴油','34');
1
2
3
4
5
6
7
8
9
10
11/*将基表的ename字段修改了*/
update v_emp set ename='kitty' where empno=7839;
/*将视图包含的deptno均修改为20,在基表中修改*/
update v_emp set deptno = 20;
/*结果集为空,基表中不存在10号部门了*/
select * from v_emp where deptno = 10;
/*with check option保证视图查询条件不被修改,但其他字段可以修改*/
create view v_emp as select * from emp where deptno = 10 with check option;With check option作用:
1
2
3
4
5
6
7
8
9
10create view IS_student
as
select sno,sname,sage
from student
where sdept='IS'
with check option;
--- 加上了with check option;后,不能执行以下插入操作:
insert into is_student
values('95100','李娜',12)什么原因?不加上with check option则可以!
with check option可以这么解释:
通过视图进行的修改,必须也能通过该视图看到修改后的结果。比如你insert,那么加的这条记录在刷新视图后必须可以看到;如果修改,修改完的结果也必须能通过该视图看到;如果删除,当然只能删除视图里有显示的记录。
而你只是查询出sdept='is’的纪录,你插入的根本不符合sdept='is’呀,所以就不行
可更新视图条件:
(1)若视图是由两个以上基本表导出的,则此视图不允许更新。
(2)若视图的字段来自字段表达式或常数,则不允许对此视图执行INSERT和UPDATE操作,但允许执行 DELETE操作。
(3)若视图的字段来自聚集函数,则此视图不允许更新。
(4)若视图定义中含有GROUP BY子句,则此视图不允许更新。
(5)若视图定义中含有DISTINCT短语,则此视图不允许更新。
(6)若视图定义中有嵌套查询,并且内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视 图不允许更新。
删除视图:
1
drop view v_emp; -- 删除视图(DDL操作)
注意事项:
通过视图可以修改基表数据,但视图一般只做查询。
with check option关键词用于保证视图的查询条件不被修改,但其他字段可以修改。
Ch8. Indexing(索引)
1. 定义
系统根据某种算法,将已有的数据(未来可能新增的数据),单独建立一个文件,这个文件能够实现快速匹配数据,并且能够快速的找到对应的记录,几乎所有的索引都是建立在字段之上的。
数据库索引有多种类型,常见索引包括顺序文件上的索引、B+树索引、散列(hash)索引、位图索引等
顺序文件上的索引是针对按指定属性值升序或降序存储的关系,在该属性上建立一个顺序索引文件,索引文件由属性值和相应的元组指针组成。
B+树索引是将索引属性组织成B+树形式,B+树的叶结点为属性值和相应的元组指针。B+树索引具有动态平衡的优点。
散列索引是建立若干个桶,将索引属性按照其散列函数值映射到相应桶中,桶中存放索引属性值和相应的元组指针。散列索引具有查找速度快的特点。位图索引是用位向量记录索引属性中可能出现的值,每个位向量对应一个可能值。
常用的索引类型:普通索引
、唯一索引
、组合索引普通索引和唯一索引的创建方式有三种,分别是直接创建、修改表结构创建、创建表时同时创建,注意组合索引的组合规则是最左前缀索引
2. 索引的意义:
提升查询数据的效率;
约束数据的有效性。
- 但是增加索引是有前提条件的,这是因为索引本身会产生索引文件(有的时候可能会比数据本身都大),因此非常耗费磁盘空间。
- 如果某个字段需要作为查询的条件经常使用,可以使用索引;
- 如果某个字段需要进行数据的有效性约束,也可以使用索引(主键或唯一键)。
3. 索引的类型
1 | -- 直接创建索引 |
注意:
为什么没有time这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。
简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引
4. 索引的优化
- 何时使用聚集索引或非聚集索引?
- 索引不会包含有NULL值的列
- 使用短索引
- 索引列排序
- like语句操作
- 不要在列上进行运算
总结:MySQL只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。