社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
数据库是长期存储在计算机内、有组织的、可共享的大量数据的集合。
数据库中存储的是数据及数据之间的关系。
正常情况读写文件系统比数据库快一到两个数据级;
数据库的查询,大量并发的时候可能最浪费时间的是connect和close。
数据库的优势是体现的大量数据的查询、统计以及并发读写,不是在速度上。
永久存储、有组织、可共享。
(数据的最小存取单位是数据项)
数据独立性包括:物理独立性和逻辑独立性
a)物理独立性(外模式模式映像):
用户程序不需要了解,应用程序要处理的只是数据的逻辑结构,这样当数据的物理存储改变了,应用程序不用改变。
b)逻辑独立性(模式内模式映像):
逻辑独立性是指用户的应用程序与数据库的逻辑结构是相互独立的,即,当数据的逻辑结构改变时,用户程序也可以不变。
逻辑数据独立性(logical data independence)是指概念模式改变,外模式和应用程序不变。在逻辑数据独立性里,数据的逻辑结构发生改变或存储关系的选择发生改变时用户不会受到影响。改变概念模式,例如增加和删除实体、增加和删除属性、增加和删除联系,不需要改变现有的外模式或重写应用程序。在DBMS中只需要修改视图的定义和映像来支持逻辑数据独立性。对用户来说,不再关心所做的修改是非常重要的。换句话说,模式经过逻辑重构之后,根据外模式构建的应用程序还是和从前一样工作。
概念模型的一种表示方法:实体联系方法,用E-R方法(E-R模型)来描述。
概念模型是用于信息世界的建模,是一种信息模型,与具体的DBMS无关。且能满足用户对数据的处理要求,易于修改。
概念模型与具体数据模型无关且容易向数据库模型转化。
实体:举行表示
属性:椭圆表示,并用直线与实体连接
联系:菱形表示,用直线与实体连接,同时在边上标上联系的类型(1:1,1:n,m:n)。
一个联系转化为一个关系模式,与该联系相连的各实体的码以及联系的属性转化为关系的属性,该关系的码则有三种情况:
若联系为1:1,则每个实体的码均是该关系的后选码。
若联系为1:n,则关系的码为n端实体的码。
若联系为m:n,则关系的码为诸实体码的组合。
数据库模式定义语言DDL(Data Definition Language):是用于描述数据库中要存储的现实世界实体的语言。一个数据库模式包含该数据库中所有实体的描述定义。这些定义包括结构定义、操作方法定义等。
数据库逻辑设计: 将概念设计所得到的概念模型转换为某一具体的数据模型(层次、网状、关系、面向对象).
在关系模型中,关系完整性主要是指以下三方面:
所谓的实体完整性就是指关系(所谓的关系就是表)的主码不能取空值;
比如学生表的主码通常是取学号为主码
是指参照关系中每个元素的外码要么为空(NULL),要么等于被参照关系中某个元素的主码;
参照关系也称为外键表,被参照关系也称为主键表。
指对关系中每个属性的取值作一个限制(或称为约束)的具体定义。比如 性别属性只能取”男“或”女“,再就是年龄的取值范围,可以取值0-130 ,但不能取负数,因为年龄不可能是负数。
目地:使结构更合理,消除存储异常,使数据冗余尽量小,便于插入、删除和更新。
原则:遵从概念单一化“一事一地”原则,即一个关系模式描述一个实体或实体间的一种联系。
规范的实质:概念的单一化。
规范化的方法:将关系模式投影分解成两个或两个以上的关系模式。
设X,Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。
举个例子:通过AB能得出C,通过A也能得出C,通过B也能得出C,那么说C部分依赖于AB。
设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。
举个例子:通过AB能得出C,但是AB单独得不出C,那么说C完全依赖于AB.
设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(Y !→X),Y→Z,则称Z传递函数依赖于X。
举个例子:通过A得到B,通过B得到C,但是C得不到B,B得不到A,那么成C传递依赖于A
设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,并且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系r,给定的一对(x,z)值有一组Y的值,这组值仅仅决定于x值而与z值无关。
举例:
有这样一个关系 <仓库管理员,仓库号,库存产品号> ,假设一个产品只能放到一个仓库中,但是一个仓库可以有若干管理员,那么对应于一个 <仓库管理员,库存产品号>有一个仓库号,而实际上,这个仓库号只与库存产品号有关,与管理员无关,就说这是多值依赖。
各个范式联系:
5NF⊂4NF⊂BCNF⊂3NF⊂2NF⊂1NF
如果一个关系模式R的所有属性都是不可分的基本数据项,则R∈1NF。
自我理解1NF就是无重复的列。
如:(X1,X2)→X3,X2→X3 其中x3对x2部分依赖
如:(X1,X2)→X3,X2→X4 其中有非主属性X4部分依赖于候选键{X1,X2},所以这个关系模式不为第二范式;又因为范式之间的关系满足1NF⊇2NF⊇3NF ⊇ BCNF,所以是第一范式。
若R∈1NF,且每一个非主属性完全函数依赖于码,则R∈2NF。
即要求数据库表中的每个实例或行必须可以被唯一地区分。
若R∈3NF,则每一个非主属性既不部分依赖于码,也不传递依赖于码。
自我理解是:表中所有的数据元素不但要能唯一地被主键所标识,而且他们之间还必须相互独立,不存在其他的函数关系。
所有非主属性对每一个码都是完全函数依赖;
所有主属性对每一个不包含它的码,也是完全函数依赖;
没有任何属性完全函数依赖于非码的任何一组属性。
关系模式R<U,F>∈1NF
,如果对于R的每个非平凡多值依赖X->->Y(Y∉X
),X都含有码,则称R<U,F>∈4NF
数据库管理系统(DBMS):是系统软件,是数据库系统的核心。
常见数据库管理系统有:Access、mysql、sql server
SQL 语言是非过程化的语言,易学习。
SQL语言具有两种使用方式:一种是在终端交互方式下使用,称为交互式SQL; 另一种是嵌入在高级语言的程序中使用,称为嵌入式SQL,而这些高级语言可以是C、PASCAL、COBOL等,称为宿主语言。
关系数据库系统支持 三级模式结构,其概念模式、外模式和内模式中的基本对象有表、视图和索引。
三级模式结构有效地组织、管理数据,提高了数据库的逻辑独立性和物理独立性。使数据库达到了数据独立性。
是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。是数据库系统模式结构的中间层,即不涉及数据的物理存储细节和硬件环境,也与具体的应用程序、开发工具及高级设计语言无关。
模式是数据库数据在逻辑级上的视图,一个数据库只有一个模式。
也用于区分一个 大项目中的各个小项目,这样若有相同名字的表的话, 不同模式不会发生冲突。相当于编程时的命名空间。
如:
一个公司的系统,分2个子系统,分别为财务系统和人力资源系统.
这2个子系统, 共用一个数据库。
那么 财务系统的表, 可以放在财务的模式(schema).
人力资源系统的表,放在人力资源系统的模式里面。
这2个子系统,能够互相访问对方的表。
但是又不因为 表重名 的问题,影响对方。
访问具体的一个表,可以由 4个部分组成
分别为 服务器名, 数据库名,模式名,表名。
对于访问本地的数据库:
不指定模式名的话, 数据库默认使用dbo模式。
(DBO是每个数据库的默认用户,具有所有者权限,即DbOwner )
是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。
外模式通常是模式的子集,一个数据库可以有多个外模式,但一个应用程序只能有一个外模式。
外模式是保证数据库安全性的一个有力措施:用户只能访问外模式的数据,其余数据不可见。
一个数据库只有一个内模式。
内模式是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。
数据库管理系统在三级模式之间提供了两层映像:
外模式/模式映像(保证数据的逻辑独立性)
模式/内模式映像(保证了物理独立性)
表分为临时表和永久表。
临时表存储在tempdb中(如下),当不再使用时会自动删除。
IF OBJECT_ID('tempdb..#ownerAnnouce') IS NOT NULL
根据进程独立,只有进程的拥有者有表的访问权限,其它用户不能访问该表;
不同的用户进程,创建的临时表虽然“名字”相同,但是这些表之间相互并不存在任何关系;在SQLSERVER中,通过特别的命名机制保证临时表的进程独立性。
临时表有两种类型:本地和全局。
名称以单个数字符号 (#) 打头;它们仅对当前的用户连接是可见的;当用户从 SQL Server 实例断开连接时被删除。
名称以两个数字符号 (##) 打头,创建后对任何用户都是可见的,当所有引用该表的用户从 SQL Server 断开连接时被删除。
真正的临时表利用了数据库临时表空间,由数据库系统自动进行维护,因此节省了表空间。并且由于临时表空间一般利用虚拟内存,大大减少了硬盘的I/O次数,因此也提高了系统效率。
A. create table #临时表名
B.select * into #临时表名 from 表名(永久表或临时表)
视图是一张虚拟表,视图的字段是自定义的,视图只支持查询,查询数据来源于实体表。
视图可以将多个复杂关联表提取信息,优化查询速度。
为了改变数据库的性能和可访问性所增加的一组辅助性数据。
详细介绍见下文。
在mysql中:
show databases;
create database children;
drop database children;
use children;
主键、非空、唯一取值。
create table product
(
no char(10) primary key,
code char(10) not null unique,
online char(1),
bind char(1)
);
外键:
foreign key(no) references product(no) //一个外键
//两个属性构成主键 这两个主键是外键
primary key(Sno,Cno),
foreign key(Sno) references Student(Sno)
foreign key(Cno) references Course(Cno)
数据表中添加一个字段:alter table 表名 add (字段 字段类型) [ default '输入默认值'] [null/not null] ;
修改字段类型或长度:alter table 表名 modify column 字段名 类型;
修改列名:
1、在oracle数据库中: ALTER TABLE 表名 RENAME COLUMN 列名 TO 新列名。
2、在sqlserver数据库中:exec sp_rename '[表名].[列名]‘,’[表名].[新列名]'。
3、在mysql数据库中:ALTER TABLE 表名 CHANGE 列名 新列名 列类型。
数据库处理一个查询的步骤:
客户端连接->查询缓存->解析器->预处理器->查询优化器->查询执行引擎->数据
1. 客户端发送一条查询给服务器;
2. 服务器先会检查查询缓存query cache,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段;
3. 服务器端进行SQL解析parsing、预处理transition,再由优化器optimization生成对应的执行计划;
4. 根据优化器生成的执行计划,调用存储引擎的API来执行分布distribution查询;
5. 将结果返回给客户端。
select * from student
功能 | 表达 | 举例 |
---|---|---|
等于 | = |
|
不等于 | <> 或!= |
|
空值 | is null,is not null |
select * from student where class is not null; |
确定集合 | in ,not in |
select * from student where age not in(21,23); |
确定范围 | between and , not between and |
|
模糊查询 | like ,not like |
select * from student where name like '%丽%';’ %代表任意长度(可为0)的字符串;_(下划线):代表任意单个字符。(汉字代表2个字符,所以一个汉字用两个下划线);为转义字符 |
默认为asc:升序排列。desc:降序排序。
单个排序:
select name,age from student order by age desc;
多重排序:
order by 字段5,字段6 asc //先按字段5排序,再按字段6排序
select a.title,b.type_name
from news_table as a,name_table as b
where a.type_id=b.type_id ;
--简单case函数
case sex
when '1' then '男'
when '2' then '女’
else '其他' end
--case搜索函数
case when sex = '1' then '男'
when sex = '2' then '女'
else '其他' end
应用:
select (case sex
when '1' then '男'
when '2' then '女’
else '其他' end)sex from student where class = 11;
having只能用在group by之后(即having后面紧跟组条件表达式),对分组后的结果进行筛选,筛选行(即使用having的前提条件是分组).
select class,avg(age) as age from student
group by class
having avg(age)>23 /*要求平均年龄大于23*/
where肯定在group by 之前
where后的条件表达式里不允许使用聚合函数,而having可以。
avg平均数,同min(age)、max(age)、sum(age)
select avg(age) as age from student group by class order by age desc;
select count(class)from student;
/*数量 因为使用了92标准,所以null不计入count*/
count(*) 跟count(1) 的结果一样,返回记录的总行数,都包括对NULL 的统计,
count(column) 是不包括NULL 的统计。
select distinct(class)from student;/*去重复,出现所有不同的内容*/
select count(distinct(class)) from student;
LEFT(“123456789”,LEN(“数据库”))/*分两步运算,第一步是运算LEN函数,结果是3。第二步针对123456789这个字符从左边开始连续取三个数*/
select top 100 * from student where no=11;/*显示前100行*/
select isnull(name,'无') as name,age,class from student;/*isnull之后就无列名了 用as给列重命名*/
select name,age,class,'the name is' + name as introduce from student;/*用加号形成一个自定义列*/
是数据库的一个标准。以下代码 写在存储过程前面,表示遵从SQL-92 规则。
SQL-92 标准要求在对空值进行等于 (=) 或不等于 (<) 比较时取值为 FALSE。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
即使 column_name 中包含空值,使用 WHERE column_name = NULL 的 SELECT 语句仍返回零行。
即使 column_name 中包含非空值,使用 WHERE column_name < NULL 的 SELECT 语句仍会返回零行。
SET QUOTED_IDENTIFIER ON
为ON:标识符可以由双引号分隔,而文字必须由单引号分隔。
为OFF:标识符不可加引号。
如果内层查询语句查询到符合条件的记录,就返回一个真值(true),否则,将返回
一个假值(false)。
SELECT * FROM employee
WHERE EXISTS
(SELECT d_name FROM department WHERE d_id=1003);
同理还有:NOT EXISTS。
insert into tableName(no,name) values('1','kate');
insert into product values('001','001','N','N');
有自增长主键(id)的插入:
i>可以把id的值设置为null或者0,这样mysql会自己做处理
ii>手动指定需要插入的列,不插入这一个字段的数据!
update tableName set name = 'Tom' where name='kate';
update tableName set age = age + 1;
增加列:
alter table tableName add (column)columnName varchar(30)
删除列:
alter table tableName drop (column) columnName
删除表中几行:
DELETE FROM Person WHERE LastName = 'Wilson'
删除表中所有行,保留表、不释放空间。所删除的每行记录都会进日志,可以回滚。
DELETE FROM table_name
删除表:删除内容和定义,释放空间
drop table user; //DROP TABLE IF EXISTS "public"."role_relation"; 可重复执行sql
删除表中所有数据,保留表、同时释放空间(速度比delete快,但是无法撤回,日志里面只记录页释放):
truncate table book;
列名、表名、存储过程名、函数名等都可以按需要加中括号。防止某些关键字在应用中引起歧义。
select [select] from 表名;
GRANT <权限>
ON <对象类型> <对象名>
TO <用户>
[WITH GRANT OPTION] // 如果指定了WITH GRANT OPTION子句,则获得某种权限的用户还可以把这种权限再授予其他用户,允许用户传递权限,但是不允许循环授权。
举例:
例1:把查询Student表的权限授给用户U1
GRANT SELECT
ON TABLE Student
TO U1;
例2:把全部操作权限授予用户U2和U3
GRANT ALL PRIVILEGES
ON TABLE Student,Course
TO U2,U3;
例3:把查询权限授予所有用户
GRANT SELECT
ON TABLE SC
TO PUBLIC;
REVOKE <权限>
ON <对象类型> <对象名>
FROM <用户>
举例:
例6:收回所有用户对表sc的查询权限
REVOKE SELECT
ON TABLE SC
FROM PUBLIC;
由DBA(数据库管理员,Database Administrator,简称DBA)在创建用户时实现。
CREATE USER <username>
[WITH] [DBA|RESOURCE|CONNECT]
只有系统的超级用户才有权创建一个新的数据库用户
新创建的用户有三种权限:DB,|RESOURCE,CONNECT
CREATE ROLE <角色名>
给角色授权:
GRANT <权限>
ON <对象类型> 对象名
TO <角色>
将一个角色授予其他的角色或用户
GRANT <角色1>
TO <角色3>
[WITH ADMIN OPTION]//如果指定了WITH ADMIN OPTION 子句,则获得某种权限的角色或用户还可以把这种权限再授予其他角色
角色权限的收回
REVOKE <权限>
ON <对象类型> <对象名>
FROM <角色>
在安全系统中创建一项,以拒绝给当前数据库内的安全帐户授予权限并防止安全帐户通过其组或角色成员资格继承权限。
DENY { ALL | statement [ ,...n ] }
TO security_account [ ,...n ]
和授权区别:
不授权是没有权限,但是如果这个用户属于某个角色,这个角色有了权限,那么这个用户可以从角色继承这个权限。如果选择了deny,即使这个用户属于某个具有权限的角色,他也没有权限。
可存储16字节的二进制值,其作用与全局唯一标记符(GUID)一样。GUID是唯一的二进制数:世界上的任何两台计算机都不会生成重复的GUID值。GUID主要用于在用于多个节点,多台计算机的网络中,分配必须具有唯一性的标识符。
A. 返回指定对象的对象 ID
USE master;
GO
SELECT OBJECT_ID(N'AdventureWorks.Production.WorkOrder') AS 'Object ID';
GO
B. 验证对象是否存在
USE AdventureWorks;
GO
IF OBJECT_ID (N'dbo.AWBuildVersion', N'U') IS NOT NULL
DROP TABLE dbo.AWBuildVersion;
GO
N是显式的将非unicode字符转成unicode字符,它来自 SQL-92 标准中的 National(Unicode)数据类型,用于扩展和标准化,在这里可以不用,写作object_id(PerPersonData)。
本题用到下面三个关系表:
CARD 借书卡。 CNO 卡号,NAME 姓名,CLASS 班级
BOOKS 图书。 BNO 书号,BNAME 书名, AUTHOR 作者,PRICE 单价,QUANTITY 库存册数
BORROW 借书记录。 CNO 借书卡号,BNO 书号,RDATE 还书日期
备注:限定每人每种书只能借一本;库存册数随借书、还书而改变。
CREATE TABLE BORROW(
CNO int FOREIGN KEY REFERENCES CARD(CNO),
BNO int FOREIGN KEY REFERENCES BOOKS(BNO),
RDATE datetime,
PRIMARY KEY(CNO,BNO))
SELECT CNO,借图书册数=COUNT(*)
FROM BORROW
GROUP BY CNO
HAVING COUNT(*)>5
CARD 借书卡。 CNO 卡号,NAME 姓名,CLASS 班级
BOOKS 图书。 BNO 书号,BNAME 书名, AUTHOR 作者,PRICE 单价,QUANTITY 库存册数
BORROW 借书记录。 CNO 借书卡号,BNO 书号,RDATE 还书日期
SELECT * FROM CARD c
WHERE EXISTS(
SELECT * FROM BORROW a,BOOKS b
WHERE a.BNO=b.BNO
AND b.BNAME=N'水浒'
AND a.CNO=c.CNO)
SELECT * FROM BORROW
WHERE RDATE<GETDATE()
SELECT BNO,BNAME,AUTHOR FROM BOOKS
WHERE BNAME LIKE N'%网络%'
N’string’ 表示string是个Unicode字符串
SELECT BNO,BNAME,AUTHOR FROM BOOKS
WHERE PRICE=(
SELECT MAX(PRICE) FROM BOOKS)
SELECT a.CNO
FROM BORROW a,BOOKS b
WHERE a.BNO=b.BNO AND b.BNAME=N'计算方法'
AND NOT EXISTS(
SELECT * FROM BORROW aa,BOOKS bb
WHERE aa.BNO=bb.BNO
AND bb.BNAME=N'计算方法习题集'
AND aa.CNO=a.CNO)
ORDER BY a.CNO DESC
UPDATE b SET RDATE=DATEADD(Day,7,b.RDATE)
FROM CARD a,BORROW b
WHERE a.CNO=b.CNO
AND a.CLASS=N'C01'
DATEADD(datepart,number,date)
date 参数是合法的日期表达式。number 是您希望添加的间隔数;对于未来的时间,此数是正数,对于过去的时间,此数是负数。
DELETE FROM BOOKS a
WHERE NOT EXISTS(
SELECT * FROM BORROW
WHERE BNO=a.BNO)
CREATE CLUSTERED INDEX IDX_BOOKS_BNAME ON BOOKS(BNAME)
CLUSTERED表示聚集索引。
CREATE TRIGGER TR_SAVE ON BORROW
FOR INSERT,UPDATE
AS
IF @@ROWCOUNT>0
INSERT BORROW_SAVE SELECT i.*
FROM INSERTED i,BOOKS b
WHERE i.BNO=b.BNO
AND b.BNAME=N'数据库技术及应用'
CREATE VIEW V_VIEW
AS
SELECT a.NAME,b.BNAME
FROM BORROW ab,CARD a,BOOKS b
WHERE ab.CNO=a.CNO
AND ab.BNO=b.BNO
AND a.CLASS=N'力01'
SELECT a.CNO
FROM BORROW a,BOOKS b
WHERE a.BNO=b.BNO
AND b.BNAME IN(N'计算方法',N'组合数学')
GROUP BY a.CNO
HAVING COUNT(*)=2
ORDER BY a.CNO DESC
ALTER TABLE BOOKS ADD PRIMARY KEY(BNO)
a. 将NAME最大列宽增加到10个字符(假定原为6个字符)。
ALTER TABLE CARD ALTER COLUMN NAME varchar(10)
b. 为该表增加1列NAME(系名),可变长,最大20个字符。
ALTER TABLE CARD ADD 系名 varchar(20)
建立索引是加快查询速度的有效手段。
索引建立后,系统在存取数据时会自动选择合适的索引作为存取路径,用户不能显示的选择索引。
在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复。
MySQL 在处理主键约束以及唯一性约束时,考虑周全。数据库用户创建主键约束的同时, MySQL 自动创建主索引( primary index ),且索引名称为 Primary ;
数据库用户创建唯一性索引时, MySQL 自动创建唯一性索引( unique index ),默认情况下,索引名为唯一性索引的字段名。
在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中可以重复,不要求唯一。
表中记录的物理顺序与键值的索引顺序相同。一个表只能有一个聚集索引。
用CLUSTERED表示。
优点:
查询速度快,因为一旦具有第一个索引值的记录被找到,具有连续索引值的记录也一定物理的紧跟其后。
缺点:
对表进行修改速度较慢,这是为了保持表中的记录的物理顺序与索引的顺序一致,而把记录插入到数据页的相应位置,必须在数据页中进行数据重排,降低了执行速度。在插入新记录时数据文件为了维持B+Tree 的特性而频繁的分裂调整,十分低效。
a) 聚集索引和非聚集索引的根本区别是表中记录的物理顺序和索引的排列顺序是否一致。
b) 聚集索引和非聚集索引都采用了B+树的结构,但非聚集索引的叶子层并不与实际的数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针的方式。聚集索引的叶节点就是数据节点,而非聚集索引的叶节点仍然是索引节点。
c) 非聚集索引添加记录时,不会引起数据顺序的重组。
A.某列包含了小数目的不同值。
B.排序和范围查找。
基于多个字段而创建的索引就称为组合索引。
create index idx1 on table1(col1,col2,col3) //创建
组合索引查询:最左前缀原则,即最左优先。
组合索引的第一个字段必须出现在查询组句中,这个索引才会被用到。只要组合索引最左边第一个字段出现在Where中,那么不管后面的字段出现与否或者出现顺序如何,MySQL引擎都会自动调用索引来优化查询效率。
增加了数据库的存储空间;
在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
这也是创建索引的最主要的原因。
特别是在实现数据的参考完整性方面特别有意义。
在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
优化隐藏就是指在执行查询语句、使用多表连接检索或者指定查询语句操作的对象表时,明确地指出应该使用的查询方法、连接算法或者对表的操作方式。
应尽量避免全表扫描,首先应考虑在where 及order by ,group by 涉及的列上建立索引。
(假设在字段name上建立了索引):
i> 使用了运算符!=,以及关键字not in, not exist等,认为产生的结果集很大,往往导致引擎不走索引而是走全盘扫描
ii> 对索引字段使用了函数,如where substr(name, 1, 3)=‘mark’, 导致索引无效
iii> 使用like和通配符,第一个字符是%将导致索引失效,如where name like "%ark“ (如果是ark%,则可以利用索引)
iv> order by与索引
如果order by中的字段有建立索引,同时:
1、该字段没有出现在where中,则在排序的时候需要正常排序,默认order by是升序排序, 故索引没有对排序产生有利帮助 。
2、该字段同时同时出现在where中,则在获取记录后不进行排序,而是直接利用索引, 效率变高。如select a,b,c from T WHERE a='2015-10-25' ORDER BY a,b;
mysql 会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,范围查询会导致组合索引半生效。
比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,c 可以用到索引,d 是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d 的顺序可以任意调整。
where 范围查询要放在最后(这不绝对,但可以利用一部分索引)。
特别注意:and 之间的部分可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql 的查询优化器会帮你优化成索引可以识别的形式。
where 字句有or 出现还是会遍历全表。
表的某个字段值的离散度越高,该字段越适合选作索引的关键字。
主键字段以及唯一性约束字段适合选作索引的关键字,原因就是这些字段的值非常离散。尤其是在主键字段创建索引时, cardinality (基数,集的势)的值就等于该表的行数。
考虑列中值的分布,列的基数越大,索引的效果越好。
更新频繁的字段不适合创建索引,不会出现在 where 子句中的字段不应该创建索引。
比如表中已经有a 的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
右模糊查询(321%)会使用索引,而%321 和%321%会放弃索引并使用全局扫描。
例如:
与字符串相比,整数字段占用的存储空间较少,因此,较为适合选作索引关键字。
与 text 类型的字段相比,char 类型的字段较为适合选作索引关键字。
类型为varchar(36);
类型为bigInt;
id作为唯一索引,并不总是能提高效率。对于非常小的表,大部分情况下简单的全表扫描效率更高,对于中大型的表,索引才非常有效。因为索引帮助存储快速查找到记录的同时,也会带来额外的消耗。
索引会消耗额外的物理空间的,而聚簇索引消耗的物理空间更大。当数据特别多的时候,相对于bigInt类型的自增长Id,varchar(36)类型的uuid消耗的物理空间更为明显。
在时间上:
1)uuid由于占用的内存更大,所以查询、排序速度会相对较慢;
2)在存储过程中,自增长id由于主键的值是顺序的,所以InnoDB把每一条记录都存储在上一条记录的后面。当达到页的最大填充因子时(innodb默认的最大填充因子为页大小的15/16,留出部分空间用于以后修改),下一条记录就会写入新的页面中。一旦数据按照这种方式加载,主键页就会被顺序的记录填满。而对于uuid,由于后面的值不一定比前面的值大,所以InnoDB并不能总是把新行插入的索引的后面,而是需要为新行寻找合适的位置(通常在已有行之间),并分配空间,这会增加额外的很多工作。这也是为什么当索引的列过长的时候,需要采用前缀索引,或者哈希索引了。
尽管自增长id的优点这么多,但实际大型项目中却很少采用自增长id的,这是为什么呢?uuid几乎保证了不同数据库的不同表的id唯一,可以进行数据切分合并,而自增长id只能保证一个数据库中的一张表的id唯一,进行数据库合并的话并然会因主键冲突而失败,这是一个硬伤。
并(∪)、差(-)、交(∩)、笛卡尔积(×)
笛卡尔积(直积):表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。
例如,A={a,b}, B={0,1,2},则
A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
在关系R中选择满足给定条件的诸元组。
关系R上的投影是从R中选择出若干属性列组成新的关系。
投影之后可既改变行,又改变元组的数量。
从两个关系的笛卡尔积中选取属性间满足一定条件的元组。(连接由乘积(笛卡尔积)、选择、投影组成)
分为等值连接(=)、自然连接(要求比较的分量是相同的属性组,并在结果中把重复的属性列去掉)。
RS÷S的意义就是:“在R和S的联系RS中,找出与S中所有的元组有关系的R元组”。
非与或
主键唯一且不为空。
不允许修改外码
级连操作:当删除或修改被参照表时,同时删除或修改参照表中的不一致元祖。
是用户定义在关系表上的一类由事件驱动的特殊过程。一旦定义,任何用户对标的增删改操作均由服务器自动激活相应触发器,在DBMS核心层进行集中的完整性控制。
存储过程是一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程因为SQL 语句已经预编译过了,因此运行的速度比较快。
存储过程在服务器端运行,减少客户端的压力。
减少网络流量,客户端调用存储过程只需要传存储过程名和相关参数即可,与传输SQL 语句相比自然数据量少了很多。
可以把企业规则的运算程序写成存储过程放入数据库服务器中,由RDBMS管理,既有利于集中控制,又能够方便地进行维护。
当用户规则发生变化时,只要修改存储过程,无须修改其他应用程序。
允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程任意次,类似方法的复用。
增强了使用的安全性,充分利用系统管理员可以对执行的某一个存储过程进行权限限制,从而能够实现对某些数据访问的限制,避免非授权用户对数据的访问,保证数据的安全。程序员直接调用存储过程,根本不知道表结构是什么,有什么字段,没有直接暴露表名以及字段名给程序员。
可设定只有某些用户才具有对指定存储过程的使用权。
调试麻烦(至少没有像开发程序那样容易),可移植性不灵活(因为存储过程是依赖于具体的数据库)。
当一个事务涉及到多个SQL语句时或者涉及到对多个表的操作时就要考虑用存储过程;
当在一个事务的完成需要很复杂的商业逻辑时(比如,对多个数据的操作,对多个状态的判断更改等)要考虑;还有就是比较复杂的统计和汇总也要考虑,但是过多的使用存储过程会降低系统的移植性。
sql尽量放在存储过程中。
面对大量数据,用orcle比sql server稳定。
use test1
set ansi_nulls on
go
set quoted_identifier on
go
create procedure procedure_student
-- add the parameters for the stored procedure here
@gradeid int,
@gradename varchar(10) --传入的参数
as
begin
--计算内容
end
go
exec dbo.procedure_student 1,'g'
是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。
在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句、整个程序。
事务是恢复和并发控制的基本单元。
一个程序中包含多个事务。
事务是数据库的逻辑工作单位。要么都做,要么都不做。
事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
一个事务一旦提交,它对数据库的改变就是永久的,即处理结果得到固化。
事务隔离级别由数据库系统实现。
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们
不会相互影响, 避免各种并发问题。
在标准SQL规范中,定义了4个事务隔离级别(由低到高)。
|未授权读取(读未提交read uncommitted)|授权读取(读提交read committed)|可重复读取(repeatable read)(Mysql 的默认隔离级别)|序列化(serializable)|
|------|
|允许事务读取未被其他事务提交的变更|允许事务读取已经被其他事务提交的变更|确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新|所有事务都一个接一个地串行执行|
|可能有 脏读、不可重复读、幻读|可以避免脏读,可能有 不可重复读、幻读|可以避免脏读、不可重复读,可能会有幻读|可以避免脏读,不可重复读,幻读|
|会话a修改未提交,b读数据,a回滚了事务,导致数据不一致,这就是脏读。|会话a读数据,b修改并提交,a又读数据,数据不一致,就样就出现了同一个事务内,读的结果不一样,这就是不可重复读。|||
为了保证事务的隔离性和一致性,DBMS需要对并发操作进行正确调度。
事务T1修改数据,T2读取数据,T1由于某种原因被撤销,则数据修改回原值,但T2读取的数据是之前修改的数据,即脏数据、不正确的数据。
事务T1读数据后,T2修改了数据,T1无法再现上一次读取的结果。
事务T1读数据后,T2新增或者删除了数据,T1无法再现上一次读取的结果。
悲观锁:封锁
乐观锁:版本号、时间戳
(读取)操作创建的锁。其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。
若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
若事物T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。
用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的页将要被更新时,则升级为X锁;U锁一直到事务结束时才能被释放。
考虑一台打印机分配的例子,当有多个进程需要打印文件时,系统按照短文件优先的策略排序,该策略具有平均等待时间短的优点,似乎非常合理,但当短文件打印任务源源不断时,长文件的打印任务将被无限期地推迟,导致饥饿以至饿死。
与饥饿相关的另外一个概念称为活锁,在忙式等待条件下发生的饥饿,称为活锁。
a)忙式等待:不进入等待状态的等待。
b)阻塞式等待:进程得不到共享资源时将进入阻塞状态,让出CPU 给其他进程使用。
c)忙等待和阻塞式等待的相同之处:
在于进程都不具备继续向前推进的条件,不同之处在于处于忙等待的进程不主动放弃CPU,尽管CPU 可能被剥夺,因而是低效的;而处于阻塞状态的进程主动放弃CPU ,因而是高效的。
事务T1请求封锁R,T2请求封锁R,T3请求封锁R……
T1释放R之后,系统批准了T3的请求,然后是T4……请求,T2可能永远等待下去。(在整个过程中,事务T2 在不断的重复尝试获取锁R)。
活锁的时候,进程是不会阻塞的,这会导致耗尽CPU 资源,这是与死锁最明显的区别。
处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于死锁的实体表现为等待;活锁有一定几率解开,而死锁是无法解开的。
采用先来先服务策略。
是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或系统产生了死锁。
T1请求封锁R1,T2请求封锁R2,然后T1又请求封锁R2,T1一直等待T2释放R2,此时,T2请求封锁R1,T2将一直等待T1释放R1。
在数据库中,产生死锁的原因主要是:
两个或多个事务都已封锁了一些数据对象,然后又都请求其他事务已封锁的数据对象,从而出现死等待。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不可剥夺条件: 进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 环路等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系。
只要系统发生了死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死
锁。
预防死锁的发生只需破坏死锁产生的四个必要条件之一即可。
都不好用,一般采用死锁的诊断和解除。
a)超时法
如果一个事务等待时间超时,则认为发生死锁。(可能误判)
b)事务等待图法
事务等待图是一个有向图,反映了事务的等待情况。如果图中出现回路,就表示出现了死锁。
处理方案是:选择一个处理代价最小的事务,将其撤销并释放所有锁。
a) 从死锁进程处剥夺资源
b) 终止部分或全部进程
两段锁协议规定所有的事务应遵守的规则:
① 在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁。
② 在释放一个封锁之后,事务不再申请和获得其它任何封锁。
即事务的执行分为两个阶段:
第一阶段是获得封锁的阶段,称为扩展阶段。
第二阶段是释放封锁的阶段,称为收缩阶段。
定理:若所有事务均遵守两段锁协议,则这些事务的所有交叉调度都是可串行化的。
对于遵守两段协议的事务,其交叉并发操作的执行结果一定是正确的。值得注意的是,上述定理是充分条件,不是必要条件。一个可串行化的并发调度的所有事务并不一定都符合两段锁协议,存在不全是2PL的事务的可串行化的并发调度。
同时我们必须指出,遵循两段锁协议的事务有可能发生死锁。
此时事务T1 、T2同时处于扩展阶段,两个事务都坚持请求加锁对方已经占有的数据,导致死锁。
为此,又有了一次封锁法。一次封锁法要求事务必须一次性将所有要使用的数据全部加锁,否则就不能继续执行。因此,一次封锁法遵守两段锁协议,但两段锁并不要求事务必须一次性将所有要使用的数据全部加锁,这一点与一次性封锁不同,这就是遵守两段锁协议仍可能发生死锁的原因所在。
DFD 数据流图(Data Flow Diagram):
ER图 实体-联系图(Entity-Relationship Diagram)
java应用程序可以通过JDBC或Hibernate对数据库系统进行访问。JDBC或Hibernate提供了事务控制的接口,这些接口把事务控制相关的命令发送给数据库系统,由数据库系统来控制事务的隔离级别。
一般来说,java 应用程序访问数据库的过程是:
①加载数据库驱动程序;
②通过jdbc 建立数据库连接;
③访问数据库,执行sql 语句;
④断开数据库连接。
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使java程序员可以随心所欲地使用对象编程思想来操纵数据库。
是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC是由一系列连接(Connection)、SQL语句(Statement)和结果集(ResultSet)构成的,其主要作用概括起来有如下3个方面: 连接(建立与数据库的连接)、查询(向数据库发起查询请求)、反馈(处理数据库返回结果)。
是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。
Statement 每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.
在JDBC应用中,应该尽可能的以PreparedStatement代替Statement。
Statement sta=con.createStatement();
ResultSet rst=sta.executeQuery(“select * from book”);
PreparedStatement是预编译的,优点:
a. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
b. 安全性高
有效防止Sql注入等问题。
c. 提高性能
对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
d. 代码的可读性和可维护性。
PreparedStatement pst=con.prepareStatement(“select * from book”);
ResultSet rst=pst.executeQuery();
CallableStatement接口扩展了 PreparedStatement(父接口),用来调用存储过程,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持
mysql连接
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/hadoop?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
//hadoop为数据库名。
driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://202.200.102.1:6666;databaseName=IMAGE_VIDEO_DEMO;
username=sa
password=123456
i>下载SQL Server 2008数据库驱动文件“msbase.jar、mssqlserver.jar、msutil.jar”
ii>导入包:File->Project Structure->Libraries导入->Modules依赖
iii>代码如下:
package com.hankcs.hanlp.database;
import java.sql.*;
public class DBUtil {
//这里可以设置数据库名称
private static String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=Character;";
private static final String USER="sa";
private static final String PASSWORD="123456";
private static Connection conn=null;
//静态代码块(将加载驱动、连接数据库放入静态块中)
static{
try {
//1.加载驱动程序
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//2.获得数据库的连接
conn=(Connection) DriverManager.getConnection(URL,USER,PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
//对外提供一个方法来获取数据库连接
public static Connection getConnection(){
return conn;
}
//测试用例
public static void main(String[] args) throws Exception{
//3.通过数据库的连接操作数据库,实现增删改查
Statement stmt = conn.createStatement();
//ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句 ,返回一个结果集(ResultSet)对象。
ResultSet rs = stmt.executeQuery("select *
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!